728x90
Reflection ?
- 구체적인 클래스 타입을 알지 못해 그 클래스의 메소드와 타입 그리고 변수들에 접근할 수 있도록 해주는 자바 API이다. 즉, 구체적인 클래스 타입을 모를때 사용하는 방법
- 컴파일 시간(Compile Time)이 아닌 실행 시간(Run Time)에 동적으로 특정 클래스의 정보를 추출
- Spring framework, Intellij 자동완성, jackson Library 등에서 사용
장점
- 확장성 특징
- 애플리케이션은 정규화된 이름을 사용하여 확장성 객체의 인스턴스를 생성하여 외부 사용자 정의 클래스를 사용할 수 있다.
- 클래스 브라우저 및 시각적 개발 환경 제공
- 클래스 브라우저는 클래스의 Method, Property, Consturctor를 열거할 수 있어야 한다.
- 시각적인 개발 환경은 개발자가 올바른 코드를 작성하는데 도움이 되도록 Reflection에서 사용할 수 있는 형식 정보를 사용
- 디버거 및 테스트 도구
- 디버거는 개인 Property, Method, Constructor를 검수할 수 있어야 한다.
- 테스트 장치는 Reflection을 사용하여 클래스에 정의된 발견 가능한 세트 API를 체계젹으로 호출하여 테스트에서 높은 수준의 코드 커버리지를 보장한다.
주의사항 및 단점
- 퍼포먼스의 오버헤드
- Reflection에는 동적으로 해석되는 유형이 포함되므로, 특정 JVM 최적화를 수행할 수 없다.
- 따라서 Reflection 작업이 성능이 떨어진다. 성능에 민감한 애플리케이션에서 자주 호출되는 코드엔 사용하지 않아야 한다.
- 보안 제한 사항
- 보안 매니저의 존재하지않는 실행 시 액세스 권한이 필요하다.
- 이것은 제한된 보안 컨텍스트에서 실행되어야 하는 코드에 대한 주요한 고려 사항이다.
- 캡슐화를 저해
- private한 Property 및 Method에 엑세스하는 것과 같이 비Reflection 코드에서 작동하지 않는 코드를 수행할 수 있다. 그래서 Reflection을 사용하면 예기치 않은 부작용이 발생하여 코드 기능이 저하되고 이식성이 손상될 수 있다.
- Relfection은 추상화를 깨트려 플랫폼 업드레이드 시 동작이 변경될 수 있다.
예시
Child.java
package hello.reflection;
public class Child{
public String cstr1 = "1";
private String cstr2 = "2";
public Child() {
}
private Child(String str) {
cstr1 = str;
}
public int method4(int n) {
System.out.println("method4: " + n);
return n;
}
private int method5(int n) {
System.out.println("method5: " + n);
return n;
}
}
Test.java
package hello.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
}
}
Class 조회
//input --> 클래스 참조 o
Class clazz = Child.class;
System.out.println("clazz: " + clazz.getName());
//input --> 클래스 참조 x
Class clazz1 = Class.forName("hello.reflection.Child");
System.out.println("clazz: " + clazz2.getName());
//output
clazz = hello.reflection.Child
clazz1 = hello.reflection.Child
Constructor 조회
// 인자가 없는 생성자 조회
//input
Class clazz1 = Class.forName("hello.reflection.Child");
Constructor constructor = clazz1.getDeclaredConstructor();
System.out.println("constructor.getName() = " + constructor.getName());
//output
constructor.getName() = hello.reflection.Child
// 모든 생성자 조회
//input
Constructor constructors[] = clazz.getDeclaredConstructors();
for (Constructor cons : constructors) {
System.out.println("cons = " + cons);
}
//output
cons = public hello.reflection.Child()
cons = private hello.reflection.Child(java.lang.String)
// public 생성자 조회
//input
Constructor constructors[] = clazz.getConstructors();
for (Constructor cons : constructors) {
System.out.println("cons = " + cons);
}
//output
cons = public hello.reflection.Child()
Method 조회
// 이름으로 메서드 조회: getDeclaredMethod()
에 인자 사용
//input
Method method1 = clazz1.getDeclaredMethod("method4", int.class);
System.out.println("method1 = " + method1);
//output
method1 = public int hello.reflection.Child.method4(int)
//모든 Method 조회: 인자없는 getDeclaredMethod()
사용
//input
Method method[] = clazz1.getDeclaredMethods();
for (Method method2 : method) {
System.out.println("method2 = " + method2);
}
//output
method2 = public int hello.reflection.Child.method4(int)
method2 = private int hello.reflection.Child.method5(int)
// public메서드, 상속받은 메서드 리턴
//input
Method method2[] = clazz1.getMethods();
for (Method method3 : method2) {
System.out.println("method3 = " + method3);
}
//output
method3 = public int hello.reflection.Child.method4(int)
method3 = public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
method3 = public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
method3 = public final void java.lang.Object.wait() throws java.lang.InterruptedException
method3 = public boolean java.lang.Object.equals(java.lang.Object)
method3 = public java.lang.String java.lang.Object.toString()
method3 = public native int java.lang.Object.hashCode()
method3 = public final native java.lang.Class java.lang.Object.getClass()
method3 = public final native void java.lang.Object.notify()
method3 = public final native void java.lang.Object.notifyAll()
Field 조회
// Field 조회 - getDeclaredField()
에 전달된 이름과 일치하는 field
//input
Field field = clazz1.getDeclaredField("cstr1");
System.out.println("field = " + field);
//output
field = public java.lang.String hello.reflection.Child.cstr1
// 모든 Field 조회
//input
Field fields[] = clazz1.getDeclaredFields();
for (Field field1 : fields) {
System.out.println("field1 = " + field1);
}
//output
field1 = public java.lang.String hello.reflection.Child.cstr1
field1 = private java.lang.String hello.reflection.Child.cstr2
예
Class<Customer> customerClass = Customer.class;
Annotation[] annotations = customerClass.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Table) {
Table tableAnnotation = (Table) annotation;
System.out.println("name: " + tableAnnotation.name());
}
}
Class<Customer> customerClass = Customer.class;
Annotation tableAnnotation = customerClass.getAnnotation(Table.class);
if (tableAnnotation != null) {
System.out.println(((Table) tableAnnotation).name());
} else {
System.out.println("Table annotation is not applied to Customer class");
}
-Reference
https://medium.com/msolo021015/자바-reflection이란-ee71caf7eec5
https://docs.oracle.com/javase/tutorial/reflect/