Java
간단 예제로 이해하는 Java 리플렉션
녹녹1
2025. 4. 20. 19:12
현장에서 설계 단계가 거의 끝나가며 이제 개발을 시작하고 있습니다. 공통 부분의 경우 부장님께서 만드신 코드를 함께 사용하기에 코드를 보던 중 낯선 방식의 코드가 보여 검색해 보니 ‘리플렉션(Reflection)’이라는 개념임을 알게 되었습니다.
그래서 이번 글에서는 리플렉션이 무엇인지 정리하고, 간단한 예제를 통해 그 동작 원리를 살펴보려 합니다.
1. 리플렉션(Reflection)이란 무엇인가?
- 리플렉션은 컴파일 시점에 알 수 없는 클래스·메서드·필드 정보를 런타임에 꺼내와 조작할 수 있는 기능입니다
- 동적 유연성: 문자열로 전달된 클래스 이름만 알고 있어도 객체를 생성하거나, 메서드를 호출하거나, 필드를 읽고 쓸 수 있습니다.
- 활용 예: 프레임워크(예: Spring, Hibernate)는 리플렉션으로 객체 의존성 주입(DI), 매핑, AOP 등 다양한 동적 기능을 구현합니다.
2. 주요 메서드와 역할
기능 메서드 설명
클래스 로드 | Class.forName("com.pkg.MyClass") | 문자열 클래스명을 사용해 Class<?> 객체로 로드 |
생성자 조회 | clazz.getDeclaredConstructor(ParamType.class,…) | 지정 파라미터 시그니처를 갖는 생성자를 반환 |
객체 생성 | ctor.newInstance(arg1,…) | 조회한 Constructor로 실제 인스턴스를 생성 |
메서드 호출 | clazz.getMethod("methodName", ParamType.class…) + invoke() | 런타임에 메서드 정보를 가져와, 해당 인스턴스에서 호출 |
필드 접근·수정 | clazz.getDeclaredField("fieldName") + setAccessible(true) + get()/set() | private 필드도 포함해 값을 읽거나 쓸 수 있음 |
3. 리플렉션의 장·단점
장점
- 유연성: 컴파일 시점에 타입을 몰라도 동적 로딩·생성·호출이 가능
- 프레임워크 지원: 스프링의 DI, Hibernate의 ORM 매핑 등 많은 라이브러리가 리플렉션에 기반
단점
- 성능 오버헤드: 런타임에 검사·호출 과정이 추가되어 일반 코드보다 느려질 수 있습니다 .
- 가독성 저하: 코드가 복잡해지고, 컴파일 타임 타입 체크가 불가능해 런타임 오류 위험이 높아집니다.
4. 예제
다음은 문자열로 클래스명을 알고 있을 때 리플렉션으로 객체를 생성하고, 메서드를 호출해 필드를 세팅·출력하는 예제입니다.
📁 ProductVO.java
public class ProductVO {
private String name;
private int price;
public ProductVO() { /* 기본 생성자 */ }
public void setName(String name) { this.name = name; }
public void setPrice(int price) { this.price = price; }
public void printInfo() {
System.out.println("상품명: " + name + ", 가격: " + price + "원");
}
}
📁 ReflectionExample.java
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// 1) 클래스 이름으로 로드
Class<?> clazz = Class.forName("ProductVO");
// 2) 기본 생성자 조회
Constructor<?> ctor = clazz.getConstructor();
// 3) 객체 생성
Object product = ctor.newInstance();
// 4) 메서드 조회 및 호출
Method setName = clazz.getMethod("setName", String.class);
Method setPrice = clazz.getMethod("setPrice", int.class);
Method printInfo = clazz.getMethod("printInfo");
setName.invoke(product, "치킨");
setPrice.invoke(product, 20000);
// 5) 출력
printInfo.invoke(product);
}
}
코드 역할
Class.forName("ProductVO") | 문자열로 클래스를 불러옴 |
getConstructor() | 기본 생성자를 가져옴 |
newInstance() | 객체 생성 |
getMethod() | 메서드 정보 가져옴 |
invoke() | 해당 메서드를 호출함 |
🔍 출력 결과
상품명: 치킨, 가격: 20000원