Reflection

hee·2026년 5월 19일

JAVA

목록 보기
6/6

자바의 리플렉션은 클래스나 메서드의 메타정보를 이용해 메서드를 동적으로 호출하는 방법이다.

@Slf4j
static class Hello {
	public String callA() {
		log.info("callA");
		return "A";
	}
	public String callB() {
		log.info("callB");
		return "B";
	}
}
@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);
}

이 예시코드에서는 부가 기능 사이에 핵심 기능이 있고, 해당 핵심 기능은 계속해서 변화하기에 메서드로 따로 빼내기에 애매하다.

// 이렇게 쪼개면...
void logStart() { log.info("start"); }
void logResult(String result) { log.info("result = {}", result); }

// 쓸 때는 여전히 중복이 남고 지저분합니다.
logStart();
String result1 = target.callA();
logResult(result1);

logStart();
String result2 = target.callB();
logResult(result2);

예를들어 메서드로 따로 뺀다 하더라도 이렇게 중복이 남고 지저분한 코드가 완성된다.

따라서, 해당 문제를 해결하기 위해 리플렉션을 사용한다. 클래스와 메서드의 정보를 빼내어 동적으로 사용하는 방식이다.

@Test
void reflection1() throws ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, IllegalAccessException {

    // 경로로 클래스의 메타정보를 가져와 리플렉션 객체를 생성한다.
    Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
    // 실제 객체를 생성한다.
    Hello target = new Hello();
    
    // 리픒렉션 객체에서 매서드 정보를 가져온다.
    Method methodCallA = classHello.getMethod("callA");
    // 매서드가 호출될 객체를 파라미터로 넣는다.
    // 호출의 결과를 Object로 반환한다.
    Object result1 = methodCallA.invoke(target);
    log.info("result = {}", result1);

    Method methodCallB = classHello.getMethod("callB");
    Object result2 = methodCallB.invoke(target);
    log.info("result = {}", result2);
}

invoke() 메서드를 이용해 해당 메서드를 호출하게 되고, 결과를 Object 타입으로 변환시키는 것이다. 이때 주의해야할 점은 invoke() 메서드의 파리미터로는 실제 객체가 들어가야한다.

@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);
}

조금 더 간소화 하자면 이렇다.

하지만 리플렉션은 런타임시 동작하기 때문에 컴파일 시점에 오류를 알 수 없다는 단점이 존재한다. 따라서, 리플렉션의 사용을 최대한 지양한다.

0개의 댓글