Reflection API 란, 구체적인 클래스 타입을 알지 못해도 그 클래스의 정보(메서드, 타입, 변수 등)에 접근할 수 있게 해주는 자바 API 이다.

public class Car {
    private final String name;
    private int position;

    public Car(String name, int position) {
        this.name = name;
        this.position = position;
    }

    public void move() {
        this.position++;
    }

    public int getPosition() {
        return position;
    }
}

다음과 같은 Car 객체가 있다. 자바의 특징인 다형성 덕분에 아래와 같이 객체 생성이 가능하다.

public static void main(String[] args) {
    Object obj = new Car("foo", 0);
}

Car 객체를 Object 타입으로 생성하였다. obj 객체는 타입이 Object 이므로 Car 객체에 있던 move()getPosition() 에 접근할 수 없다.

자바는 컴파일러를 사용한다. 즉, 컴파일 타입에 타입이 결정된다. obj 라는 이름의 객체는 컴파일 타입에 Object 로 타입이 결정되었기 때문에 Object 클래스의 인스턴스 변수와 메서드만 사용할 수 있다.

obj 는 Object 클래스라는 타입만 알 뿐, Car 클래스에 대해서는 알지 못한다. 결국 컴파일러가 있는 자바는 구체적인 클래스를 모르면 해당 클래스의 정보에 접근할 수 없다.

Reflection 의 사용

public static void main(String[] args) throws Exception {
    Object obj = new Car("foo", 0);
    Class carClass = Car.class;
    Method move = carClass.getMethod("move");

    // move 메서드 실행, invoke(메서드를 실행시킬 객체, 해당 메서드에 넘길 인자)
    move.invoke(obj, null);

    Method getPosition = carClass.getMethod("getPosition");
    int position = (int)getPosition.invoke(obj, null);
    System.out.println(position);
    // 출력 결과: 1
}
Class carClass2 = Class.forName("Car");

위의 예제처럼 클래스와 메서드의 이름 만으로도 해당 클래스의 정보를 가져올 수 있다. 즉, Reflection API 는 클래스의 이름만 가지고도 생성자, 필드, 메서드 등 해당 클래스에 대한 거의 모든 정보를 가져올 수 있다.

자바에서는 JVM 이 실행되면 사용자가 작성한 자바 코드가 컴파일러를 거쳐 바이트 코드로 변환되어 static 영역에 저장된다. Reflection API 는 이 static 영역에 저장된 값을 가져온다.

Reflection 의 활용

Reflection 은 애플리케이션 개발보다는 프레임워크나 라이브러리에서 많이 사용된다. 프레임워크나 라이브러리는 사용자가 어떤 클래스를 만들지 예측할 수 없기 때문에 동적으로 해결해주기 위해 Reflection 을 사용한다.

실제로 intellij 의 자동완성, jackson 라이브러리, Hibernate 등등 많은 프레임워크나 라이브러리에서 Reflection 을 사용하고 있다.

Spring Framework 에서도 Reflection API 를 사용하는데 대표적으로 Spring Container 의 BeanFactory 가 있다. Bean 은 애플리케이션을 실행한 후 런타임에 객체가 호출될 때 동적으로 객체의 인스턴스를 생성하는데 이때 Spring Container 의 BeanFactory 에서 리플렉션을 사용한다.

Spring Data JPA 에서 Entity 에 기본 생성자가 필요한 이유도 동적으로 객체 생성 시 Reflection API 를 활용하기 때문이다. Reflection API 로 가져올 수 없는 정보 중 하나가 생성자의 인자 정보이다. 그래서 기본 생성자가 반드시 있어야 객체를 생성할 수 있는 것이다. 기본 생성자로 객체를 생성만 하면 필드 값 등은 Reflection API 로 넣어줄 수 있다.

https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/