Java의 리플렉션(Reflection)

CosmoNumb·2024년 10월 22일
1

java

목록 보기
24/24

리플렉션(Reflection)은 자바에서 클래스, 메서드, 필드 등의 구조를 런타임에 동적으로 탐색하고 조작할 수 있게 해주는 기능이다. 즉, 컴파일 시점이 아닌 런타임에 객체의 정보에 접근하여 필드 값을 읽거나 쓰고, 메서드를 호출하거나, 객체를 생성할 수 있게 해 준다.

예를 들어, 특정 클래스의 객체를 생성할 때 일반적으로 new 클래스명() 같은 방법을 사용하지만, 리플렉션을 사용하면 클래스명을 문자열로 입력받아도 객체를 동적으로 생성할 수 있다. 이렇게 하면 프로그램이 동적으로 동작할 수 있는 유연성을 제공하게 된다.

리플렉션을 통해 할 수 있는 일

  1. 클래스의 정보 조회: 클래스의 이름, 메서드, 필드, 생성자 등을 런타임에 확인할 수 있다.
  2. 동적 객체 생성: 코드가 실행 중일 때 클래스의 인스턴스를 동적으로 생성 가능하다.
  3. 메서드 호출: 메서드의 이름을 문자열로 받아 해당 메서드를 실행할 수 있다.
  4. 필드 값 읽기/쓰기: 필드에 직접 접근하여 값을 읽거나 수정할 수 있다. 일반적으로는 private 접근 제어자가 있더라도 접근이 가능하다.

Hibernate의 관계?

Hibernate는 리플렉션 기능을 사용한다. 여기서 리플렉션을 사용하는 이유는 JPA 엔티티를 관리할 때, 개발자가 명시적으로 메서드를 호출하지 않아도 내부적으로 객체를 생성하고 필드를 설정할 수 있어야 하기 때문이다. 예를 들어, Hibernate는 데이터베이스에서 값을 가져올 때 엔티티 객체를 자동으로 생성하고, 그 객체의 필드 값을 설정해야 한다. 이때 리플렉션을 통해 기본 생성자를 호출하고 필드에 값을 주입하는 방식으로 작업을 처리한다.

Hibernate가 JPA 엔티티를 관리할 때, 다음과 같은 작업을 리플렉션을 통해 수행한다:

  • 기본 생성자를 호출해서 객체를 만들고,
  • 필드 값에 데이터베이스에서 가져온 값을 설정한다.

즉, 개발자가 직접 객체를 생성하지 않아도, Hibernate는 리플렉션을 통해 필요한 객체를 만들어 관리할 수 있다.

백엔드 개발자가 리플렉션을 알아야 하는 이유

  • 일반적인 백엔드 개발자JPA나 Hibernate의 동작 원리를 이해하기 위해 리플렉션의 기본 개념을 알 필요가 있다. 리플렉션이 Hibernate 내부에서 자동으로 처리되는 부분이지만, 이를 이해하면 JPA의 동작 방식을 더 잘 이해할 수 있다.
  • 프레임워크나 라이브러리 개발을 할 때, 리플렉션이 자주 사용되기 때문에 필요하다.
  • 고급 JPA 기능이나 Hibernate 커스터마이징을 할 때 리플렉션을 이해하면 도움이 된다.

리플렉션의 장단점

장점

  • 동적 프로그래밍: 런타임에 객체의 메타데이터(클래스 정보, 메서드 등)에 접근할 수 있어 매우 유연하다. Hibernate 같은 프레임워크가 이러한 특성을 활용해 객체를 자동으로 관리한다.

단점

  • 성능 이슈: 리플렉션을 사용하면 일반적인 메서드 호출보다 성능이 느릴 수 있다. 하지만 Hibernate는 성능 최적화를 위해 내부적으로 리플렉션을 효율적으로 사용한다.
  • 안전성: 컴파일 시점에 오류를 찾기 어렵기 때문에, 런타임 시 오류가 발생할 가능성이 있다.

리플렉션 예시 코드

아래는 리플렉션을 사용한 예제 코드이다. 코드의 주요 부분마다 설명을 추가했으며, 보다 이해하기 쉽게 작성되었다.

import java.lang.reflect.*;

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        // 1. 클래스의 정보 조회
        Class<?> clazz = Class.forName("com.example.MyClass");

        // 2. 동적 객체 생성 (기본 생성자 호출)
        Object obj = clazz.getDeclaredConstructor().newInstance();
        
        // 3. 메서드 호출 (메서드 이름을 문자열로 받아서 실행)
        Method method = clazz.getMethod("sayHello");
        method.invoke(obj); // 동적으로 메서드 호출
        
        // 4. 필드 값 읽고 쓰기
        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true); // private 필드 접근 허용
        field.set(obj, "New Name"); // 필드 값 설정
        System.out.println("Updated Name: " + field.get(obj)); // 필드 값 출력
    }
}
  • Class<?> clazz = Class.forName("com.example.MyClass");
    이 코드는 문자열로 클래스 이름을 받아 MyClass의 정보를 가져온다.
  • clazz.getDeclaredConstructor().newInstance();
    기본 생성자를 호출해 객체를 동적으로 생성한다.
  • Method method = clazz.getMethod("sayHello");
    sayHello라는 메서드를 가져와서 method.invoke(obj);로 호출한다.
  • Field field = clazz.getDeclaredField("name");
    name이라는 필드를 가져와 값 설정과 읽기가 가능하도록 한다.

리플렉션은 매우 강력한 기능이지만, 성능에 약간의 부담이 생길 수 있고, 코드의 가독성이나 유지보수성을 떨어뜨릴 수 있으므로 필요할 때만 사용해야 한다.

결론

  • JPA를 사용하는 백엔드 개발자리플렉션의 기본 개념만 이해하고 있어도 충분하다. JPA를 사용할 때 리플렉션을 직접 다룰 필요는 거의 없다..고 한다.
  • 리플렉션이 Hibernate 내부에서 어떻게 동작하는지에 대한 깊은 이해는 필수가 아니며, 고급 기능이나 프레임워크 커스터마이징을 할 때 더 많이 사용된다.

1개의 댓글

comment-user-thumbnail
2024년 10월 22일

+) getClass() -> 객체의 런타임 클래스를 나타내는 Class 객체를 반환함. 이 메서드는 리플렉션을 사용하여 런타임에 객체의 클래스 정보를 얻는 데 사용될 수 있으며, 객체의 클래스 타입을 확인할 때 유용하다.

답글 달기