리플렉션(Reflection)이란?
자바 리플렉션은 프로그램 실행 중(런타임)에 클래스의 정보를 분석하고, 클래스의 필드, 메소드, 생성자 등에 접근하여 조작할 수 있는 능력을 제공합니다. 이는 컴파일 때는 알 수 없는 클래스를 동적으로 조작하고 활용할 수 있는 기능을 제공하며, 메타프로그래밍을 위한 핵심 개념입니다.
리플렉션을 활용하여 클래스의 메타데이터를 분석하고, 필드와 메서드를 동적으로 조작하거나 호출할 수 있습니다. 리플렉션 API로 클래스의 인스턴스를 생성하고, 필드 값을 읽거나 수정하고, 메서드를 호출하는 등의 작업을 수행할 수 있습니다. 이를 통해 프레임워크, 플러그인 시스템, 유연한 코드 구현 등을 가능하게 합니다.
리플렉션 API
java.lang.Class:
`getName()`: 클래스의 이름을 반환
Class<?> clazz = ExampleClass.class;
String className = clazz.getName();
System.out.println(className); // 출력: "com.example.ExampleClass"
`getDeclaredMethods()`: 클래스의 모든 메서드를 반환
Class<?> clazz = ExampleClass.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
`getDeclaredFields()`: 클래스의 모든 필드를 반환
Class<?> clazz = ExamleClass.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
`getFields()`: 클래스의 public 필드를 반환
Class<?> clazz = ExampleClass.class;
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
`getDeclaredConstructors()`: 클래스의 모든 생성자를 반환
Class<?> clazz = ExampleClass.class;
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor.getName());
}
`getDeclaredAnnotations()`: 클래스에 선언된 모든 어노테이션을 반환
Class<?> clazz = ExampleClass.class;
Annotation[] annotations = clazz.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.annotationType().getName());
}
`getSuperclass()`: 클래스의 상위 클래스(부모 클래스)를 반환
public class Example {...}
public class ChildExample {...}
Class<?> ExampleSuperclass = Example.class.getSuperclass(); // Object 클래스 반환
Class<?> ChildExampleSuperclass = ChildExample.class.getSuperclass(); // Example 클래스 반환
java.lang.reflect.Method:
`invoke()`: 특정 객체의 메서드를 호출
Class<?> clazz = ExampleClass.class;
Method method = clazz.getDeclaredMethod("methodName", parameterTypes);
method.setAccessible(true);
Object result = method.invoke(myObject, arguments);
`getParameterTypes()`: 메서드의 매개변수 타입들을 반환
Class<?> clazz = ExampleClass.class;
Method method = clazz.getDeclaredMethod("methodName", parameterTypes);
Class<?>[] parameterTypes = method.getParameterTypes();
`getReturnType()`: 메서드의 반환 타입을 반환
Class<?> clazz = ExampleClass.class;
Method method = clazz.getDeclaredMethod("methodName", parameterTypes);
Class<?> returnType = method.getReturnType();
java.lang.reflect.Field:
`get()`: 특정 객체의 필드 값을 반환
Class<?> clazz = ExampleClass.class;
Field field = clazz.getDeclaredField("fieldName");
field.setAccessible(true);
Object value = field.get(myObject);
`getType()`: 필드의 타입을 반환
Class<?> clazz = ExampleClass.class;
Field field = clazz.getDeclaredField("fieldName");
Class<?> fieldType = field.getType();
`getModifiers()`: 필드의 접근 제한자와 기타 플래그 반환
Class<?> clazz = ExampleClass.class;
Field field = clazz.getDeclaredField("fieldName");
int modifiers = field.getModifiers();
`set()`: 특정 객체의 필드 값을 설정
Class<?> clazz = ExampleClass.class;
Field field = clazz.getDeclaredField("fieldName");
field.setAccessible(true);
field.set(myObject, value);
java.lang.reflect.Constructor:
`newInstance()`: 클래스의 생성자를 호출하여 객체를 생성
Class<?> clazz = ExampleClass.class;
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
Object myObject = constructor.newInstance(arguments);
java.lang.reflect.Modifier:
`isPublic()`: 접근 제한자가 public인지 확인
Class<?> clazz = ExampleClass.class;
int modifiers = clazz.getModifiers();
boolean isPublic = Modifier.isPublic(modifiers);
`isPrivate()`: 접근 제한자가 private인지 확인
Class<?> clazz = ExampleClass.class;
int modifiers = clazz.getModifiers();
boolean isPrivate = Modifier.isPrivate(modifiers);
리플렉션의 사용처
런타임에 클래스 정보 분석
리플렉션은 런타임에 클래스의 정보를 분석할 수 있으므로, 동적으로 클래스의 필드, 메소드, 주석 등을 알아낼 수 있습니다. 이를 통해 다양한 자동화 작업이 가능해지며, 예를 들어 특정 클래스에 특정 어노테이션이 붙은 메서드들을 실행할 수 있습니다.
Class<?> clazz = ExampleClass.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(ExampleClass.class)) {
method.invoke(myObject);
}
}
동적 객체 생성 및 접근
리플렉션은 클래스의 생성자를 동적으로 호출하여 객체를 생성할 수 있습니다. 이를 통해 런타임 시에 동적으로 객체를 생성 및 접근하거나, 프레임워크에서 객체를 자동으로 생성하는 등의 유연한 구현이 가능해집니다.
Class<?> clazz = ExampleClass.class;
Constructor<?> constructor = clazz.getConstructor(String.class);
ExampleClass myObject = (MyClass) constructor.newInstance("example");
프레임워크 / 라이브러리
프레임워크나 라이브러리를 개발할 때, 리플렉션을 사용하여 사용자 정의 클래스의 인스턴스를 동적으로 생성하고, 메소드를 호출하며, 필드 값을 조작하는 등의 작업을 수행할 수 있습니다.
고려해야 할 사항
리플렉션은 일반적인 코드 실행보다 성능이 낮을 수 있습니다. 이는 리플렉션 API가 추가적인 작업을 수행하기 때문입니다. 따라서 성능이 중요한 부분에서는 리플렉션 사용을 신중하게 고려해야 합니다.
리플렉션을 사용하면 접근 제한자에 관계없이 클래스의 멤버에 접근할 수 있습니다. 하지만 이는 객체 지향 원칙을 위배할 수 있으며, 논리적인 오류를 초래할 수 있습니다. 리플렉션을 사용할 때에는 접근 제한을 존중하고, 필요한 경우에만 사용하는 것이 좋습니다.
'Java' 카테고리의 다른 글
Java란 무엇인가? (0) | 2024.09.05 |
---|---|
Java Apache POI로 엑셀(Excel) 파일 조작하기 (0) | 2023.07.06 |
Java 어노테이션(@annotation)을 활용한 커스텀 메타데이터 만들기 (0) | 2023.07.05 |
Java 직렬화와 역직렬화: 객체 저장과 복원을 위한 기술 (0) | 2023.06.28 |
Java java.io 기반 입출력: 입출력 스트림, 콘솔 입출력, 파일 입출력, 보조 스트림 (0) | 2023.06.26 |