ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 리플렉션이란?
    Java 2022. 4. 7. 19:34

    공부를 하다가 Reflection이라는 키워드를 듣고 해당 키워드에 대해서 전혀 모르겠어서 알아보고자 합니다.

     

    Reflection API란?

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

     

    Reflection을 잘 나타낸 문장이지만 처음 공부하는 사람은 무슨 말인지 한 번에 이해하기 쉽지 않습니다.

     

    아래와 같이 Car 클래스가 존재합니다.

    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;
        }
    }

     

    자바의 특징 중 하나인 다형성 덕분에 아래와 같이 객체 생성이 가능합니다.

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

    그러면 이렇게 생성된 obj라는 이름의 객체가 Car 클래스의 move 메서드를 사용할 수 있을까요?

    불가능합니다.

     

    자바는 컴파일러를 사용합니다.

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

     

    그러므로 아래와 같은 코드는 필연적으로 컴파일 에러가 발생합니다.

    public static void main(String[] args) {
        Object obj = new Car("foo", 0);
        obj.move();    // 컴파일 에러 발생 java: cannot find symbol
    }

    생성된 obj라는 객체는 Object 클래스라는 타입만 알 뿐, Car 클래스라는 구체적인 타입은 모릅니다.

    결국 구체적인 클래스를 모르면 해당 클래스의 정보를 접근할 수 없습니다.

     

    하지만 Reflection API를 활용하면 이것을 가능하게 해 줍니다.

    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
    }

    위의 예제처럼 클래스의 이름만으로도 해당 클래스의 정보를 가져올 수 있습니다.

    즉, Reflecction API는 클래스의 이름만 가지고도 생성자, 필드, 메서드 등등 해당 클래스에 대한 거의 모든 정보를 가져올 수 있는 마법 같은 API입니다.

     

    어떻게 가능할까요?

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

    Reflection API는 이 정보를 활용하여 클래스 이름만 알고 있다면 언제든 static 영역을 뒤져서 정보를 가져올 수 있습니다.

     

     

    어디에 활용할 수 있을까요?

    보통 위의 예제처럼 구체적인 클래스를 모를 일이 거의 없기 때문에 멀쩡한 Car 객체를 Object 타입으로 생성할 필요는 없습니다.

     

    Reflection API의 단점

    • Reflection API의 특성상 컴파일 타임이 아닌 런타임에 동적으로 타입을 분석하고 정보를 가져오므로 JVM을 최적할 할 수 없기 때문에 성능 오버헤드가 존재합니다.
    • 직접 접근할 수 없는 private 인스턴스 변수, 메서드에 접근하기 때문에 내부를 노출하면서 추상화가 깨집니다.

     

    결론적으로 Reflection은 애플리케이션 개발보다는 프레임워크나 라이브러리에서 많이 사용됩니다.

    프레임워크나 라이브러리는 사용자가 어떤 클래스를 만들지 예측할 수 없기 때문에 동적으로 해결해주기 위해 Reflection을 사용합니다.

     

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

     

    Spring Framework에서의 활용

    Spring Framework에서도 Reflection API를 사용하는데 대표적으로 Spring Container의 BeanFactory가 있습니다.

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

     

    Spring Data JPA에서의 활용

    Spring Data JPA에서 Entity에 기본 생성자가 필요한 이유도 동적으로 객체 생성 시 Reflection API를 활용하기 때문입니다.

    Reflection API로 가져올 수 없는 정보 중 하나가 생성자의 인자 정보이기 때문에 반드시 기본 생성자가 있어야 객체를 생성할 수 있습니다.

    기본 생성자로 객체를 생성만 하면 필드 값 등은 Reflection API로 넣어줄 수 있습니다.

     

     

    결론

    Java Reflection API에 대해 친숙해지는 계기가 되었으며 Spring Fraemwork, JPA 등을 학습하면서 reflection에 관한 내용을 접하게 된다면 '프레임워크에서 구체적이지 않은 객체를 동적으로 해결해주는구나'로 이해하면 좋을 것 같습니다.

     

     

     

     

    출처

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

     

    Reflection API 간단히 알아보자.

    Spring Framework를 학습하다 보면 Java Reflection API를 자주 접하게 된다. 하지만 Reflection API…

    tecoble.techcourse.co.kr

     

    'Java' 카테고리의 다른 글

    [Java] 빌더 패턴  (0) 2022.04.09
    [Java] 프록시 패턴이란?  (0) 2022.04.08
    [Java] 직렬화(Seralize)란?  (0) 2022.03.24
    [Java] Integer.parseInt() vs Integer.valueOf()  (0) 2022.03.20
    [Java] try-catch와 try-with-recources  (0) 2022.03.13

    댓글

Designed by Tistory.