리플렉션은 프로그램 실행 중 클래스, 객체, 메소드 및 필드의 구조와 동작을 조사하고 변경할 수 있는 메커니즘입니다. 이는 java.lang.reflect 패키지를 통해 구현됩니다.
할 수 있는 것:
예시:
import java.lang.reflect.Method; public class ReflectionExample { public void greet() { System.out.println("Hello!"); } public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("ReflectionExample"); Object instance = clazz.getDeclaredConstructor().newInstance(); Method method = clazz.getMethod("greet"); method.invoke(instance); // 출력: Hello! } }
장점:
단점/위험:
리플렉션을 통해 클래스의 private 필드 및 메소드에 접근할 수 있나요? 그 결과는 무엇인가요?
답변: 네, Field 또는 Method의 setAccessible(true) 메소드를 통해 가능합니다:
Field field = clazz.getDeclaredField("privateField"); field.setAccessible(true); field.set(obj, "value");
이는 클래스의 캡슐화를 위반하며 위험을 동반합니다: 상황이 취약해지고 보안 오류가 발생할 수 있으며 새로운 JVM 버전에서는 이러한 행위가 접근 정책에 의해 제한될 수 있습니다.
이야기
대형 프로젝트에서 리플렉션을 통해 DTO의 자동 매핑을 구현하면서 "Optional" 유형의 필드를 올바르게 처리하지 않아 대량 데이터 처리 시 NullPointerException이 발생했습니다. 리플렉션 패키지는 Optional 값과 null을 구분하지 않았기 때문입니다.
이야기
은행 소프트웨어에서 직렬화를 위해 setAccessible(true)를 통해 private 필드에 접근하는 기능이 구현되었습니다. JVM 업데이트 후 동작이 변경되어 private 필드에 대한 접근이 차단되었고, 중요한 직렬화 기능이 갑자기 프로덕션에서 작동하지 않게 되었습니다.
이야기
ORM 프레임워크에서 프록시 객체를 생성할 때 데이터 스키마 변경 후 리플렉션 캐시를 갱신하는 것을 잊어서 새로운 클래스 필드와의 작업 시 예기치 않은 예외가 발생했습니다. 새로운 필드가 캐시에 반영되지 않았기 때문입니다.