Programming Language/Java / / 2025. 3. 8. 09:09

Reflection

리플렉션 (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 멤버 접근으로 인한 보안 취약점이 발생할 수 있습니다.

 


 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유