Dipa's document :: [JAVA] Class 클레스 - getClasss(), forName(), Reflection(리플렉션), newInstance()

Class클레스란?

자바의 클레스와 인터페이스의 메타데이터(클레스의 이름, 생성자의 정보, 필드 정보, 메소드 정보)등등을 관리 하는 클레스이다.

즉, 클레스 안의 멤버 변수와 메소드 등등의 리턴 타입이라던지...파라메터값 등등을 알 수 있다는 뜻이다.

그 중에서 오늘은 getClass(), forName()를 살펴보고자 한다. 


저 두개의 메소드의 공통점은 무엇일까? 일단 힌트는 둘다 Class의 정보를 받아볼수 있는 메소드이다.

코드를 통해 살펴보자..

 
  
public final native Class<?> getClass();
 
public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

일단 둘다 공통점은 Class를 return한다는 것이다. 

차이점은? 

getClass() 같은경우는 Object클레스에 있는 메소드로써 객체를 생성을 한뒤 호출 할 수 있는 메소드이다.

forName() 같은경우는 객체를 생성하기 전에 직접 객체를 얻을 수 있다.

package api_class._class;
 
public class Car {
	private String model;
	private String owner;
	
	public Car(){
		
	}
	
	public Car(String model){
		this.model = model;
	}
	public String getModel() {
		return model;
	}
	public void setModel(String model) {
		this.model = model;
	}
	public String getOwner() {
		return owner;
	}
	private void setOwner(String owner) {
		this.owner = owner;
	}
}
package api_class._class;
 
public class ClassExample {

	public static void main(String[] args) {
		Car car = new Car();
		Class clazz1 = car.getClass();
		System.out.println(clazz1.getName());
		System.out.println(clazz1.getSimpleName());
		System.out.println(clazz1.getPackage().getName());
		
		System.out.println();
		
		try {
			Class clazz2 = Class.forName("api_class._class.Car");
			System.out.println(clazz2.getName());
			System.out.println(clazz2.getSimpleName());
			System.out.println(clazz2.getPackage().getName());
		} catch (ClassNotFoundException e) {
			System.out.println("존재하지 않은 클레스");
		}
		
	}

}

위의 소스는 단지 클레스의 이름에 대한 정보만 나와있다.. 하지만 생성자, 필드 메소드의 정보도 얻을수 있다고 하였는데?

당연 정보를 얻어 올수 있다!! 이것이 바로 Reflection(리플렉션)이다.

각각의 정보를 얻어 올수 있는 메소드 (생성자 - getDeclaredConstructors(), 필드 - getDeclareFields(), 메소드 - getDeclaredMethods() ) 이다. 

이들의 리턴값은 각각의 타입에 대한 배열이다. (왜냐하면,, 여러개 있을수 있으니까?)

하지만 저들의 메소드는 그 클레스에 선언된 것만 가져온다. 만약 상속된 멤버 까지 가져오고 싶다면.. 중간에 Declare를 뺴면된다..? 쉽죠? ㅋㅋ

이제 각각의 정보를 가져오는 소스를 보도록 하자

package api_class._class;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionExample {

	public static void main(String[] args) throws ClassNotFoundException {
		try {
			Class clazz = Class.forName("_class.Car");
			System.out.println("[생성자 정보]");
			Constructor[] constructors = clazz.getDeclaredConstructors();
			for(Constructor constructor : constructors){
				System.out.print(constructor.getName() + "(");
				Class[] parameters = constructor.getParameterTypes();
				printParameters(parameters);
				System.out.println(")");
			}
			
			System.out.println();
			
			System.out.println("[필드 정보]");
			Field[] fields = clazz.getDeclaredFields();
			
			for(Field field : fields){
				System.out.println(field.getType().getSimpleName() + " " + field.getName());
			}
			System.out.println();

			System.out.println("[메소드 정보]");
			Method[] methods = clazz.getDeclaredMethods();
			for(Method method : methods){
				System.out.print(method.getReturnType().getSimpleName() + " " + method.getName() + "(");
				Class[] parameters = method.getParameterTypes();
				printParameters(parameters);
				System.out.println(")");
			}
			
		} catch (ClassNotFoundException e) {
			System.out.println("클레스가 없음");
		}
		
	}
	
	static void printParameters(Class[] parameters){
		for(int i=0;i<parameters.length;i++){
			System.out.print(parameters[i].getName());
			if(i<(parameters.length-1)){
				System.out.print(",");
			}
		}
	}

}

이제 마지막으로 그렇다면.. 이들을 정보만 알지말고 객체를 new연산자를 이용해서 생성하지 않고, 메소드를 호출하여 사용할 수 있을까?

그것이 바로 newInstance()를 이용하여 사용할 수있다. newInstance()는 new연산자를 이용하여 객체를 생성을 하지않고, 동적으로 객체를 생성하여, runtime시에 발생을 하게 된다.

package api_class._class;

public interface Action {
	public void execute();
}


package api_class._class;

public class ReceiveAction implements Action{

	@Override
	public void execute() {
		System.out.println("데이터를 받습니다.");
	}
	
}


package api_class._class;

public class SendAction implements Action{

	@Override
	public void execute() {
		System.out.println("데이터를 보냅니다.");
	}
	
}


package api_class._class;

public class NewInstanceExample {

	public static void main(String[] args) {
		try {
			Class clazz = Class.forName("_class.ReceiveAction");
			Action action = (Action) clazz.newInstance();
			action.execute();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

}


'SH.Language > Java' 카테고리의 다른 글

[JAVA] Wrapper 클레스  (0) 2018.01.04
[JAVA] String, StringBuffer, StringBuilder 클레스  (0) 2018.01.02
[JAVA] Object클레스 - clone()  (0) 2017.12.14
[JAVA] Object클레스 - toString()  (0) 2017.12.11
[JAVA] Object클레스 - hashCode()  (0) 2017.12.06
Posted by SH후니
,