리플렉션 (Reflection)
리플렉션은 런타임에 자바 코드의 구조를 검사하고 조작할 수 있는 강력한 기능입니다.
마치 거울처럼 프로그램 자체를 들여다보고 분석하는 것처럼 동작하기 때문에 '리플렉션(reflection)'이라고 불립니다.
좀 더 자세히 설명하면, 리플렉션은 컴파일된 자바 코드에서 클래스, 메서드, 필드 등의 정보를 가져와서 런타임에 사용할 수 있게 해주는 기술입니다.
예를 들어, 클래스의 이름을 알고 있다면 리플렉션을 통해 해당 클래스의 메서드 목록, 생성자, 필드 등의 정보를 얻을 수 있습니다.
리플렉션 사용 예시
다음은 리플렉션을 사용하여 클래스 정보를 분석하고, 메서드를 호출하며, 필드 값을 변경하고, 객체를 생성하는 예시입니다.
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// 클래스 정보 얻기
Class<?> cls = Class.forName("java.lang.String");
// 클래스 정보 분석
System.out.println("클래스 이름: " + cls.getName());
System.out.println("상위 클래스: " + cls.getSuperclass().getName());
// 메서드 호출
Method method = cls.getMethod("length");
String str = "Hello, world!";
int len = (int) method.invoke(str);
System.out.println("문자열 길이: " + len);
// 필드 값 변경 (주의: String은 불변 객체이므로 실제 값이 변경되지 않음)
Field field = cls.getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[]) field.get(str);
value[0] = 'J';
System.out.println("변경된 문자열 (실제 변경되지 않음): " + str);
// 객체 생성
Constructor<?> constructor = cls.getConstructor(String.class);
String newStr = (String) constructor.newInstance("New String");
System.out.println("새로운 문자열: " + newStr);
}
}
주요 기능 상세 설명
클래스 정보 분석
클래스의 이름, 수정자, 상위 클래스, 인터페이스 등의 정보를 얻을 수 있습니다.
Class<?> cls = Class.forName("java.lang.String");
System.out.println("클래스 이름: " + cls.getName());
// 클래스 이름: java.lang.String
System.out.println("상위 클래스: " + cls.getSuperclass().getName());
// 상위 클래스: java.lang.Object
메서드 호출
런타임에 메서드를 이름으로 찾아서 호출할 수 있습니다. 심지어 private 메서드에도 접근 가능합니다.
Method method = cls.getMethod("length");
String str = "Hello, world!";
int len = (int) method.invoke(str);
System.out.println("문자열 길이: " + len);
// 문자열 길이: 13
필드 값 변경
런타임에 필드의 값을 읽거나 수정할 수 있습니다. (주의: String은 불변 객체이므로 실제 값이 변경되지 않습니다.)
Field field = cls.getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[]) field.get(str);
value[0] = 'J';
System.out.println("변경된 문자열 (실제 변경되지 않음): " + str);
// 변경된 문자열 (실제 변경되지 않음): Hello, world!
객체 생성
런타임에 동적으로 객체를 생성할 수 있습니다.
Constructor<?> constructor = cls.getConstructor(String.class);
String newStr = (String) constructor.newInstance("New String");
System.out.println("새로운 문자열: " + newStr);
// 새로운 문자열: New String
리플렉션의 활용
- 스프링 프레임워크: 의존성 주입, 애노테이션 처리 등을 구현합니다.
- 직렬화/역직렬화: 객체의 상태를 저장하거나 네트워크를 통해 전송할 때 사용됩니다.
- 테스팅 프레임워크 (JUnit): private 메서드 호출, 내부 상태 검증 등에 사용됩니다.
- 동적 프록시: 런타임에 인터페이스 구현체를 생성하고 메서드 호출을 가로챕니다.
주의사항
- 캡슐화 위반: private 필드나 메서드에 접근할 수 있으므로 캡슐화를 위반할 수 있습니다.
- 성능 저하: 런타임에 클래스 정보를 분석하고 조작하므로 성능 오버헤드가 발생합니다.
- 런타임 오류: 컴파일 시점에 타입 검사를 할 수 없어 런타임 오류가 발생할 수 있습니다.
- 보안 문제: private 멤버 접근으로 인한 보안 취약점이 발생할 수 있습니다.
'Programming Language > Java' 카테고리의 다른 글
| 공변성 & 반공변성 & 불공변성? (0) | 2025.03.17 |
|---|---|
| [EFFECTIVE JAVA] Comparable을 구현할지 고려하라 (0) | 2025.03.12 |
| [Collection] Enum? (0) | 2025.03.06 |
| [Collection] Map 인터페이스와 주요 구현체 학습 (0) | 2025.03.06 |
| Jackson 라이브러리 (0) | 2025.03.05 |
