리플렉션
리플렉션 개요
리플렉션은 실행 시점에 클래스 정보를 동적으로 분석하고 객체 메서드를 호출하는 기술입니다. JVM은 각 클래스에 대해 단일 Class 객체를 생성하며, 이 객체는 클래스의 구조 정보를 포함합니다.
리플렉션 핵심 클래스
| 클래스 | 기능 |
|---|---|
| Class | 클래스 메타데이터 표현 |
| Field | 클래스 필드 조작 |
| Method | 메서드 실행 관리 |
| Constructor | 생성자 제어 |
// Class 객체 획득 방법
Class<?> cls1 = Class.forName("com.example.Employee");
Class<?> cls2 = Employee.class;
Class<?> cls3 = new Employee().getClass();
리플렉션 활용 예제
public class Employee {
private String id;
public Employee() {}
public Employee(String id) { this.id = id; }
}
// 생성자를 통한 객체 생성
Constructor<?> cons = Class.forName("com.example.Employee")
.getDeclaredConstructor(String.class);
cons.setAccessible(true);
Object obj = cons.newInstance("E123");
리플렉션 사용 시나리오
- 프레임워크 의존성 주입
- 동적 프록시 생성
- 애노테이션 처리기 구현
- 런타임 클래스 로딩
객체 생성 기법
객체 복제
얕은 복제는 참조 필드를 공유하며, 깊은 복제는 중첩 객체까지 새로 생성합니다.
class Department implements Cloneable {
private String name;
@Override
protected Object clone() {
Department dept = null;
try { dept = (Department) super.clone(); }
catch (CloneNotSupportedException e) { /* 처리 */ }
return dept;
}
}
객체 직렬화
직렬화는 객체를 바이트 스트림으로 변환합니다. transient 필드는 직렬화에서 제외됩니다.
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private transient String password; // 직렬화 제외
}
제네릭
제네릭 특성
제네릭은 컴파일 시점에 타입 안정성을 제공하며, 런타임에는 타입 정보가 삭제됩니다.
제네릭 구현 방식
// 제네릭 클래스
public class DataContainer<T> {
private T content;
public void set(T item) { content = item; }
public T get() { return content; }
}
// 제네릭 메서드
public <U> void processItem(U item) {
System.out.println(item.getClass());
}
타입 경계
// 상한 경계
List<? extends Number> numList = new ArrayList<Integer>();
// 하한 경계
List<? super Integer> intList = new ArrayList<Number>();
어노테이션
메타 어노테이션
@Target: 적용 대상 지정@Retention: 생명주기 설정@Documented: 문서 포함 표시@Inherited: 하위 클래스 상속
커스텀 어노테이션
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomRule {
String category() default "Validation";
int priority() default 1;
}
어노테이션 처리
Method method = targetClass.getMethod("validateData");
if (method.isAnnotationPresent(CustomRule.class)) {
CustomRule rule = method.getAnnotation(CustomRule.class);
System.out.println("Rule Priority: " + rule.priority());
}