java.lang.reflect
패키지 아래에서 리플렉션에 필요한 클래스들이 제공된다..getClass()
: 오브젝트가 속한 클래스의 이름을 얻을 수 있다..getConstructors()
: 오브젝트가 속한 클래스의 public 생성자를 얻을 수 있다..getMethods()
: 오브젝트가 속한 클래스의 공개된 메소드들을 얻을 수 있다.위와 같은 메소드들을 통해서 런타임에 해당 클래스 혹은 메소드의 행위를 검증 혹은 수정할 수 있다.
public class ReflectionTest {
private String str;
public ReflectionTest() {
str = "ReflectionTest";
}
public void publicMethod() {
System.out.println("str = " + str);
}
public void publicMethodWithArg(int arg) {
System.out.println("arg = " + arg);
}
private void privateMethod() {
System.out.println("(private) str = " + str);
}
@Test
public void reflectionTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ReflectionTest reflectionTest = new ReflectionTest();
Class reflectionTestClass = reflectionTest.getClass();
System.out.println("reflectionTestClass.getName() = " + reflectionTestClass.getName());
Constructor constructor = reflectionTestClass.getConstructor();
System.out.println("constructor.getName() = " + constructor.getName());
Method publicMethodWithArg = reflectionTestClass.getDeclaredMethod("publicMethodWithArg", int.class);
publicMethodWithArg.invoke(reflectionTest, 15);
// 접근 제어자에 상관없이 메소드를 호출하는 방법
Method privateMethod = reflectionTestClass.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(reflectionTest);
Method[] methods = reflectionTestClass.getMethods();
for (Method method : methods) {
System.out.println("reflectionTestClass method = " + method);
}
}
}
reflectionTestClass.getName() = reflection_test.ReflectionTest
constructor.getName() = reflection_test.ReflectionTest
arg = 15
(private) str = ReflectionTest
reflectionTestClass method = public void reflection_test.ReflectionTest.publicMethodWithArg(int)
reflectionTestClass method = public void reflection_test.ReflectionTest.reflectionTest() throws java.lang.NoSuchMethodException,java.lang.reflect.InvocationTargetException,java.lang.IllegalAccessException
reflectionTestClass method = public void reflection_test.ReflectionTest.publicMethod()
reflectionTestClass method = public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
reflectionTestClass method = public final void java.lang.Object.wait() throws java.lang.InterruptedException
reflectionTestClass method = public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
reflectionTestClass method = public boolean java.lang.Object.equals(java.lang.Object)
reflectionTestClass method = public java.lang.String java.lang.Object.toString()
reflectionTestClass method = public native int java.lang.Object.hashCode()
reflectionTestClass method = public final native java.lang.Class java.lang.Object.getClass()
reflectionTestClass method = public final native void java.lang.Object.notify()
reflectionTestClass method = public final native void java.lang.Object.notifyAll()
Process finished with exit code 0
이를테면, 자바에서 알 수 없는 타입의 오브젝트를 갖고 있고 만일 해당 오브젝트에 .doSomething()
이라는 메소드가 있다면 수행하는 동작을 만들고 싶은데, 해당 오브젝트가 알려진 인터페이스를 따르지 않는다면 자바의 정적 타이핑 시스템은 이러한 동작을 지원할 수 없다. 리플렉션을 이용하면, 코드에서 해당 오브젝트에 .doSomething()
메소드가 있는지 알아내고 만일 있다면 실행하는 동작이 가능하다.
Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);
애노테이션과 함께 쓰이는 유명한 실제 용례 중 하나는 JUnit4
에서 @Test
애노테이션이 있는 클래스와 메소드들을 찾아볼 때, Reflection
기술을 사용 후 유닛 테스트가 동작할 때 @Test
애노테이션이 붙은 것을 호출한다.
사실 위의 용례에서 메소드가 있는지 검사하고 있으면 수행하는 방식은 자주 쓰이는 방식은 아니다. 하지만 애노테이션이 붙었는지 확인 후에 실행하거나 하는 방식은 여전히 많이 쓰인다.
이러한 개념은 다른 정적 타입 언어(C#)에 있는 Reflection
과도 매우 비슷하다.
오브젝트 타입을 확인하는 것은 정확히
Reflection
의 역할은 아니고,Type Introspection
이라고 한다.Reflection
은Introspection
을 이용하여 런타임 중에 동작을 변화시키는 것을 말한다. C++와 같은 언어는Reflection
은 지원하지 않고Introspection
만 지원하기 때문에 이 같은 구분을 명확히 해두면 좋다.
확장성 기능 (Extensibility Features)
: 오브젝트의 완전한 이름을 사용하여 확장성 오브젝트들의 인스턴스를 만들어냄으로써 애플리케이션이 외부, 사용자 정의 클래스들을 사용할 수 있게 된다.디버깅과 테스트 도구 (Debugging and testing tools)
: 클래스의 private 멤버를 검사하기 위해 디버거가 리플렉션의 프로퍼티를 사용할 수 있다.성능 오버헤드
: 리플렉션 연산은 당연히 리플렉션이 없는 것보다 느리다. 그래서 자주 호출되는 성능에 민감한 코드에는 적용하지 말아야 한다.내부의 노출
: 리플렉션 코드는 추상화를 파괴하고 플랫폼의 업그레이드 시 동작이 변경될 수도 있다.https://www.geeksforgeeks.org/reflection-in-java/
https://stackoverflow.com/questions/37628/what-is-reflection-and-why-is-it-useful