Class.forName 사용하기
JAVA.LANG.CLASS클래스
클래스의 정보를 얻기위한 클래스
즉, 클래스의 정보를 얻어오는 클래스입니다.
forName() : 물리적인 클래스 파일명을 인자로 넣어주면 이에 해당하는 클래스를 반환해줍니다.
클래스를 조사하기 위한 클래스입니다.
변수로 클래스를 만들때 Class.forName 은 유용하게 쓰인다.
예제소스 (물리적인 WhitePerson 클래스를 인스턴스한다.)
try{
Class c = Class.forName("poly.WhitePerson");
// 로딩단계(클래스조사),메모리에 올라오지는 않음(newInstance()해줘야함)
Person p=(WhitePerson)c.newInstance();
// newInstance() 반환형이 Object형이므로 다운캐스팅한다.
}catch(ClassNotFoundException e1){
//클래스를 찾지못했을 경우에 대한 예외사항
System.out.println("클래스가 존재하지 않습니다.");
}catch(InstantiationException e2){
//인스턴스(new)실패시에 대한 예외사항
System.out.println("메모리에 올릴수 없습니다.");
}catch(IllegalAccessException e3){
//파일접근에 대한 예외사항
System.out.println("클래스파일 접근 오류입니다.");
}
종합예제 소스
물리적(폴더)에 있는 클래스 (WhitePerson/BlackPerson/YellowPerson)
를 입력받아 해당클래스를 로딩&생성하여 속성(color 변수)에 대한 값을 출력!!!!!
[1] 사용자가 입력한 문자열에 해당하는 클래스를 얻어옵니다.
[2] 얻어온 클래스를 메모리에 올린후
[3] 해당 메서드를 실행합니다.
1. package classtest;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import poly.*;
public class ClassApp extends JFrame implements ActionListener{
private JPanel p;
private JLabel la;
private JTextField txt1, txt2;
private JButton bt;
public ClassApp(){
p=new JPanel();
la=new JLabel("생성할 클래스 입력");
txt1=new JTextField(15);
txt2=new JTextField(15);
bt=new JButton("생성");
p.add(txt1);
p.add(bt);
p.add(txt2);
add(p);
bt.addActionListener(this);
setSize(200,150);
setVisible(true);
}
public void actionPerformed(ActionEvent ae){
String className = txt1.getText();
try{
Class c=Class.forName(className);
// 로딩단계(클래스조사), 메모리에 올라오지는 않음
Person p = (Person)c.newInstance();
txt2.setText(p.getColor());
}catch(ClassNotFoundException e1) {
//클래스를 찾지못했을 경우에 대한 예외사항
txt2.setText("클래스가 없습니다.");
}catch(InstantiationException e2){
// 인스턴스(new)실패시에 대한 예외사항
txt2.setText("인스턴스를 생성할수 없습니다.");
}catch(IllegalAccessException e3){
//파일접근에 대한 예외사항
txt2.setText("엑세스 할수 없습니다.");
}
}
public static void main(String[] args){
new ClassApp();
}
}
Class.forName() 와 ClassLoader.loadClass() 차이점
일단 Class.forName() 메서드는 인자가 한 개 짜리인 것과 세 개 짜리인 것이 있습니다.
static Class<?> forName(String className)
Returns the Class object associated with the class or interface with the given string name.
static Class<?> forName(String name, boolean initialize, ClassLoader loader)
Returns the Class object associated with the class or interface with the given string name, using the given class loader.
1. 클래스를 로딩할 때 사용되는 클래스로더 차이
인자가 한개 짜리인 forName(String) 메서드는 클래스를 로딩할 때 사용하는 클래스로더가 저 코드를 실행하는 클래스로더가 됩니다. 하지만 ClassLoader.loadClass()를 사용하면 당연히 자기 자신을 사용해서 클래스 로딩을 실행하게 되죠.
(그렇다고 해서 반드시 해당 클래스로더가 읽어온다는 보장은 없죠. 그 부모가 읽어올 수도 있고 클래스 패스에 없을 수도 있고 암튼 여기서 로딩한다는 건 로딩을 시도한다고 보시기 바랍니다.)
하지만 Class.forName(String, boolean, ClassLoader)를 사용하면 클래스 로더를 지정해 줄 수 있습니다.
2. 초기화
Class.forName(String) 메서드를 사용하면 곧바로 클래스의 static 초기화 블럭과 static 멤버 변수의 값을 초기화 합니다. 하지만 ClassLoader.loadClass()를 사용하면 해당 클래스를 처음으로 사용하기 전까지 초기화가 지연됩니다.
이것 역시 Class.forName(String, boolean, ClassLoader)의 두번째 인자값을 이용하여 조절할 수 있습니다.
- 클래스 초기화 에러
만약 Class.forName(String)을 사용해서 로딩할 때 static 영역에서 에러가 난다면 해당 클래스는 다시 로딩할 수가 없습니다. 특정 클래스로더가 일단 로딩한 클래스는 다시 로딩할 수가 없죠.
그래서 NoClassDefinitionFound 에러가 날 수도 있습니다.
이때는 해당 클래스로더 인스턴스를 버리고 새로 만들어야 하는데 그럴 때를 대비해 인자 세개짜리 forName을 쓰라는군요.
결국 forName()으로 클래스를 로딩할 떄는 별 개의 클래스로더를 쓰라는건데 그렇게 단순해 보이지가 않는데 클래스로더를 지정해 둔다고 해봤자. 보통 App CL로 읽어올테고 그럼 App CL 인스턴스를 버리라고?? 그건 좀..
forName으로 읽어올 클래스를 클래스패스를 가지고 있으면서 parent로 위임하지도 않는 CL을 이용해서 forName으로 읽은 경우라면 뭐 괜찮을지도 모르겠습니다. 어쨋거나 직접 통제가 가능한 클래스로더를 사용해야 겠네요.
'JAVA' 카테고리의 다른 글
[JAVA] ClassLoader (0) | 2017.10.30 |
---|---|
[JAVA]classes 위치 가져오기 (0) | 2017.10.30 |
[JAVA] class 클래스 로딩 (0) | 2017.10.30 |
[JAVA] class 동적로딩 (0) | 2017.10.30 |
[JAVA] class path에서 resource 찾기 (0) | 2017.10.30 |