본문 바로가기
JAVA/[JAVA] 바구니

[JAVA] Reflection

by oncerun 2020. 4. 21.
반응형

Reflection은 객체를 통해 클래스의 정보를 분석해내는 프로그램 기법입니다.

정보란 멤버 변수, 메서드, 인터페이스, 생성자 을 말하며 객체를 생성하거나 변수를 변경할 수 있고 메서드를 호출할 수도 있습니다.

 

Reflection은 객체를 통해 클래스의 정보를 분석해내는 프로그램 기법입니다.

정보란 멤버 변수, 메서드, 인터페이스, 생성자 을 말하며 객체를 생성하거나 변수를 변경할 수 있고 메서드를 호출할 수도 있습니다.

우선적으로 reflection을 사용하기 앞서
import java.lang.reflect.*; 를 임포트 해줍니다.

첫 번째로 Class 클래스입니다.
java.lang.Class이며 lang패키지 안에 존재하므로 import 하지 않고 사용할 수 있습니다.
Class 클래스는 자바에서 사용되는 클래스들에 대한 구조를 가지고 있는 Class입니다.

package blog;

public class A extends B{

	public String str1 = "안녕하세요";
	public int num = 3;
	private String str2 = "안녕하세요";
	public A() {
	}
	private A(int num) {
		this.num = num;
	}
	public A(String str2) {
		this.str2 = str2;
	}

	public void method1() {
		System.out.println("method1");
	}

	public void method2(int a) {
		System.out.println(a);
	}

	private void method3(int a , String b) {
		System.out.println("method3");
		System.out.printf("int %d String %s",a,b);
	}
}


-----------------------------
package blog;

public class B {
	public String a;
	
}


A라는 클래스의 정보를 가져오기 위해 Class를 사용해보겠습니다.

클래스의 이름만을 가지고 클래스 정보를 가져옵니다.

Class cls = Class.forName("blog.A");
//forName()는 패키지를포함한 경로를 설정해줍니다.
Class cls2 = A.class;
//클래스명.class로 클래스정보를 가져올 수도 있습니다.

 

이제 클래스의 정보가져왔으니 생성자의 정보를 가져오겠습니다.

인자 없는 생성자를 가져오는 방법입니다.

package blog;
import java.lang.reflect.Constructor;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor cons = cls.getDeclaredConstructor();
	System.out.println(cons);
	}

}

인자가 존재하는 생성자를 가져오기 위해선 getDeclaredConstructor(type)을 사용합니다.

같은 type의 생성자를 리턴합니다

package blog;
import java.lang.reflect.Constructor;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor cons = cls.getDeclaredConstructor(String.class);
	System.out.println(cons);
	}

}
결과 :public blog.A(java.lang.String)

 

다음 코드는 모든 생성자를 가져옵니다. getDeclaredConstructors();

package blog;
import java.lang.reflect.Constructor;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor[] cons = cls.getDeclaredConstructors();
	for(int i = 0; i < cons.length; i ++)
	System.out.println(cons[i]);
	
	}

}
결과 :  public blog.A(java.lang.String)
		private blog.A(int)
		public blog.A()

 

public 생성자만 조회하기위해선 getDeclaredConstructors();

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	
	Constructor[] cons = cls.getConstructors();
	for(int i = 0; i < cons.length; i ++)
	System.out.println(cons[i]);
	
	}

}
결과 : public blog.A(java.lang.String)
	   public blog.A()

 

이제 클래스의 메소드를 가져옵니다.

모든 메소드를 찾으려면, 다음과 같이 getDeclaredMethods를 사용하면 됩니다.

공통적으로 함수 이름에 Declared가 들어가면 Super 클래스의 정보는 가져오지 않습니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Method[] method = cls.getDeclaredMethods();
	
	for(int i= 0 ; i<method.length; i ++)
		System.out.println(method[i]);
	}

}
결과 public void blog.A.method1()
public void blog.A.method2()
public void blog.A.method3()

 

모든 메서드 말고 찾고자 하는 메서드만을 찾을 수 있습니다. 파라미터 값에 찾고자 하는 메서드 이름과 타입을 매개변수로 넣어줍니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Method method = cls.getDeclaredMethod("method2",int.class);
	
		System.out.println(method);
	}

}
결과 : public void blog.A.method2(int)

 

만약 인자가 두 개 이상이라면 배열로 인자 값을 넘겨줍니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Class type[] = {int.class, String.class};
	Method method = cls.getDeclaredMethod("method3",type);
	
		System.out.println(method);
	}

}
결과 : public void blog.A.method3(int,java.lang.String)

 

getMethods()는 public이며  자신의 메서드와 상속받은 메서드 모두를 리턴해줍니다. 

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
	Class cls = Class.forName("blog.A");
	Method[] method = cls.getMethods();
	
	for(int i= 0; i < method.length; i ++)
		System.out.println(method[i]);
	}

}

결과 : public void blog.A.method1()
public void blog.A.method2(int)
public void blog.A.method3(int,java.lang.String)
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

 

 

field 멤버변수의 정보를 얻어오겠습니다.

매개변수와 동일한 멤버변수를 찾아줍니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException {
		
	Class cls = Class.forName("blog.A");
	Field field = cls.getDeclaredField("str2");
	System.out.println(field);
	}
}

결과 : private java.lang.String blog.A.str2

 

객체에 선언된 모든 Field를 찾으려면 getFields()를 사용하면 됩니다.

public인 멤버변수와 상속받은 필드까지 가져옵니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException {
		
	Class cls = Class.forName("blog.A");
	Field[] fields = cls.getFields();
	for(Field fi : fields) {
		System.out.println(fi);
	}
	}
}

결과 :public java.lang.String blog.A.str1
public int blog.A.num
public java.lang.String blog.B.a

 

자신 필드에 대한 필드만 가져오기 위해서는 getDeclaredFields()를 사용하면 됩니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException {
		
	Class cls = Class.forName("blog.A");
	Field[] fields = cls.getDeclaredFields();
	for(Field fi : fields) {
		System.out.println(fi);
	}
	}
}
결과 :public java.lang.String blog.A.str1
public int blog.A.num
private java.lang.String blog.A.str2

 

Field 값 수정

 

클래스의 멤버 변수를 가져와서 값을 변경할 수 있습니다.

A클래스에 있는 str1의 멤버 변수의 정보를 가져와 값을 출력하고 변경해보겠습니다.

 

출력

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Field field = cls.getField("str1");
	System.out.println(field.get(a));
	
	}
}
결과 :안녕하세요

 

변경

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Field field = cls.getField("str1");
	field.set(a, "감사합니다.");
	System.out.println(field.get(a));
	
	}
}
결과 :감사합니다.

private 변수를 수정하려면  setAccessible(true)로 접근 상태를 변경하면 됩니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Field field = cls.getDeclaredField("str2");
	field.setAccessible(true);
	field.set(a, "잘먹었습니다.");
	System.out.println(field.get(a));
	
	}
}
결과 :잘먹었습니다.

 

 

 

Method 호출

클래스로부터 메서드 정보를 가져와, 객체의 메서드를 호출할 수 있습니다.

 

메서드 객체를 생성하고 invoke()로 호출합니다.

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Method method = cls.getDeclaredMethod("method2", int.class);
	int value = (int) method.invoke(a, 30);
	}
}
결과 :30

 

private 메서드를 호출할 때는 setAccessible(true) 설정해주면 됩니다.

 

package blog;
import java.lang.reflect.*;

public class Program {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
	A a = new A();
	Class cls = Class.forName("blog.A");
	Method method = cls.getDeclaredMethod("method3", int.class,String.class);
	method.setAccessible(true);
	method.invoke(a, 3,"수정하기");
	}
}
결과 : method3
int 3 String 수정하기

 

반응형

'JAVA > [JAVA] 바구니' 카테고리의 다른 글

[JAVA] Collection FrameWork  (0) 2020.04.28
[JAVA] System Class  (0) 2020.04.22
[JAVA] Objects Class (3)  (0) 2020.04.17
[JAVA] Objects Class (2)  (0) 2020.04.15
[JAVA] Objects Class (1)  (0) 2020.04.15

댓글