개발은 재밌어야 한다
article thumbnail

Java의 Reflection API는 런타임에 클래스의 메타데이터에 접근하고 조작할 수 있도록 해줍니다. Reflection을 활용하면 객체의 클래스 정보를 동적으로 확인하고, 객체의 메서드 호출, 필드 접근 등도 가능해지죠. 성능과 보안상의 이슈도 있을 수 있으니 신중한 접근이 필요합니다. 이 글에서는 Reflection의 기본 개념과 활용 방법을 단계별로 설명해 보겠습니다.


Reflection API란?

Reflection은 런타임에 Java 객체의 클래스를 조사하고, 필드나 메서드 등을 동적으로 호출할 수 있는 기능입니다. 주로 다음과 같은 상황에서 사용됩니다.

 

  • 클래스 정보 확인: 클래스 이름, 메서드, 필드, 생성자 등 다양한 메타데이터를 조회할 수 있습니다.
  • 동적 객체 생성: 런타임에 클래스의 객체를 생성하고 초기화할 수 있습니다.
  • 메서드 및 필드 조작: 특정 메서드를 호출하거나, 필드 값을 읽거나 수정할 수 있습니다.
  • 비공개 멤버 접근: private 멤버에도 접근할 수 있어, 제한된 정보나 기능을 활용할 수 있습니다.

 


Reflection API 주요 클래스 및 메서드

Java Reflection API에서 가장 자주 사용되는 클래스는 Class, Method, Field, Constructor입니다. 각 클래스가 제공하는 메서드를 통해 객체의 메타데이터를 조회하고, 객체를 동적으로 생성하거나 조작할 수 있습니다.

 

Class 클래스

Class 클래스는 클래스의 메타정보를 나타내는 핵심 클래스입니다. 모든 Java 클래스는 런타임에 Class 객체로 표현됩니다. Class 객체를 통해 특정 클래스의 정보에 접근할 수 있습니다.

// 클래스 이름을 통해 Class 객체 생성
Class<?> clazz = Class.forName("com.example.MyClass");

// 객체를 통한 Class 객체 생성
Object obj = new MyClass();
Class<?> clazzFromInstance = obj.getClass();

 

Field 클래스

Field 클래스는 클래스의 멤버 변수를 나타내며, 필드 정보 조회나 값을 읽고 쓰는 작업을 수행할 수 있습니다.

// 필드 객체 가져오기
Field field = clazz.getDeclaredField("fieldName");

// 필드 접근 설정
field.setAccessible(true);

// 필드 값 읽기 및 쓰기
Object value = field.get(obj);
field.set(obj, "newValue");

Method 클래스

Method 클래스는 클래스의 메서드를 나타냅니다. 메서드를 동적으로 호출하거나 정보를 조회할 때 사용됩니다.

// 특정 메서드 가져오기
Method method = clazz.getMethod("methodName", String.class);

// 메서드 호출
Object result = method.invoke(obj, "argument");

Constructor 클래스

Constructor 클래스는 생성자를 나타내며, 객체 생성에 사용됩니다.

// 생성자 가져오기
Constructor<?> constructor = clazz.getConstructor(String.class);

// 생성자를 통한 객체 생성
Object instance = constructor.newInstance("argument");

Reflection을 활용한 동적 프로그래밍 예제

동적 객체 생성

Reflection을 사용하면 클래스 이름만 알고 있어도 런타임에 객체를 생성할 수 있습니다. 예를 들어, 문자열 형태의 클래스 이름을 사용해 객체를 생성해 보겠습니다.

public class MyClass {
    private String message;

    public MyClass(String message) {
        this.message = message;
    }

    public void printMessage() {
        System.out.println(message);
    }
}

// 동적 객체 생성 예제
Class<?> clazz = Class.forName("MyClass");
Constructor<?> constructor = clazz.getConstructor(String.class);
Object instance = constructor.newInstance("Hello, Reflection!");
Method method = clazz.getMethod("printMessage");
method.invoke(instance);  // "Hello, Reflection!" 출력

비공개 필드 접근

Reflection을 사용하면 private 필드에도 접근할 수 있습니다. 다음 예제는 private 필드의 값을 읽고 수정하는 방법을 보여줍니다.

public class MyClass {
    private String message;

    public MyClass(String message) {
        this.message = message;
    }

    public void printMessage() {
        System.out.println(message);
    }
}

// 동적 객체 생성 예제
Class<?> clazz = Class.forName("MyClass");
Constructor<?> constructor = clazz.getConstructor(String.class);
Object instance = constructor.newInstance("Hello, Reflection!");
Method method = clazz.getMethod("printMessage");
method.invoke(instance);  // "Hello, Reflection!" 출력​

인터페이스나 부모 클래스를 통한 메서드 호출

Reflection을 활용하면 런타임에 특정 인터페이스나 상위 클래스를 기반으로 메서드를 호출할 수 있습니다. 예를 들어, 인터페이스를 구현한 여러 클래스가 있을 때 런타임에 동적으로 메서드를 호출할 수 있습니다.

public interface Greetable {
    void greet();
}

public class FriendlyClass implements Greetable {
    public void greet() {
        System.out.println("Hello!");
    }
}

// 인터페이스를 통한 동적 메서드 호출
Class<?> clazz = Class.forName("FriendlyClass");
Object instance = clazz.newInstance();

if (instance instanceof Greetable) {
    Method method = clazz.getMethod("greet");
    method.invoke(instance);  // "Hello!" 출력
}​

Reflection 사용 시 주의 사항

성능 문제

Reflection은 기본적인 메서드 호출보다 성능이 떨어집니다. Reflection은 런타임에 다양한 검사를 수행하기 때문에, 반복적인 작업에서는 성능 저하가 발생할 수 있습니다. 성능이 중요한 코드에서는 Reflection 사용을 피하거나 최소화해야 합니다.

보안 문제

Reflection을 통해 비공개 멤버에 접근할 수 있으므로, 보안상의 문제가 발생할 수 있습니다. 예를 들어, Reflection으로 private 필드나 메서드에 접근하면 캡슐화 원칙이 깨집니다. 잘못된 접근을 방지하기 위해 보안 관리자가 동작을 제어할 수도 있습니다.

유지보수 문제

Reflection은 코드를 복잡하게 만들 수 있어 디버깅과 유지보수가 어려워질 수 있습니다. 특히 클래스 이름, 필드 이름 등을 하드코딩하면 코드 변경에 따른 오류 발생 가능성이 높아집니다. 따라서 안정성이 중요한 코드에서는 Reflection 사용을 신중히 결정해야 합니다.

 

profile

개발은 재밌어야 한다

@ghyeong

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!