
리플렉션
- 리플렉션 기술을 사용하면 클래스나 메서드의 메타정보를 동적으로 획득하고, 코드도 동적으로 호출할 수 있다.
- 런타임에 동작하기 때문에, 컴파일 시점에 오류를 잡을 수 없다
- 매우 중요한 공통작업이 필요한 경우에만 사용
예)
- 정적인 target.callA() , target.callB() 코드를 리플렉션을 사용해서 Method 라는 메타정보로 추상화했다. 덕분에 공통 로직을 만들 수 있게 되었다.
@Slf4j
public class ReflectionTest {
@Test
void reflection0() {
Hello target = new Hello();
log.info("start");
String result1 = target.callA();
log.info("result={}", result1);
log.info("start");
String result2 = target.callB();
log.info("result={}", result2);
}
@Test
void reflection1() throws Exception {
Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
Hello target = new Hello();
Method methodCallA = classHello.getMethod("callA");
Object result1 = methodCallA.invoke(target);
log.info("result1={}", result1);
Method methodCallB = classHello.getMethod("callB");
Object result2 = methodCallB.invoke(target);
log.info("result1={}", result1);
}
@Test
void reflection2() throws Exception {
Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
Hello target = new Hello();
Method methodCallA = classHello.getMethod("callA");
dynamicCall(methodCallA, target);
Method methodCallB = classHello.getMethod("callB");
dynamicCall(methodCallB, target);
}
private void dynamicCall(Method method, Object target) throws Exception {
log.info("start");
Object result = method.invoke(target);
log.info("result={}", result);
}
@Slf4j
static class Hello {
public String callA() {
log.info("callA");
return "A";
}
public String callB() {
log.info("callB");
return "B";
}
}
}
Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello")
: 클래스 메타정보를 획득한다. 참고로 내부 클래스는 구분을 위해 $ 를 사용한다.
classHello.getMethod("call")
: 해당 클래스의 call 메서드 메타정보를 획득한다.
methodCallA.invoke(target)
: 획득한 메서드 메타정보로 실제 인스턴스의 메서드를 호출한다. 여기서 methodCallA 는 Hello 클래스의 callA() 이라는 메서드 메타정보이다. methodCallA.invoke(인스턴
스) 를 호출하면서 인스턴스를 넘겨주면 해당 인스턴스의 callA() 메서드를 찾아서 실행한다. 여기서는 target 의 callA() 메서드를 호출한다.