JAVA

17. Reflection(Annotation)

ggomjiu 2025. 4. 29. 03:25

Reflection

: 구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API

- JVM은 클래스 정보를 클래스 로더를 통해 읽어와서 해당 정보를 JVM 메모리에 저장

- 힙 영역에 로드된 Class 타입의 객체를 통해, 원하는 클래스의 인스턴스를 생성할 수 있도록 지원

- 컴파일된 자바 코드에서 역으로 클래스를 불러서 메소드 및 변수를 구해오는 방법

- 동적 로딩하여 사용할 때 많이 사용되고 디 컴파일할 때에도 자주 사용되는 기법

- Reflection 기능을 지원하지 않는 언어들 :  C, C++, Pascal

- 장단점)

  • 장점
    • 런타임 시점에서 클래스의 인스턴스를 생성하고, 접근 제어자와 관계 없이 필드와 메서드에 접근하여 필요한 작업을 수행할 수 있는 유연성을 지님
  • 단점
    • 일반 메서드 호출보다 성능이 훨씬 떨어짐
      • Reflection API는 컴파일 시점이 아니라 런타임 시점에서 클래스를 분석하기에 JVM을 최적화 할 수 없어서 성능 저하 발생
    • 컴파일 시점에서 타입 체크 기능을 사용할 수 없음
    • 코드가 지저분해지고 장황해짐
    • 내부를 노출해서 추상화를 파괴함
      • 접근할 수 없는 필드, 메서드에 접근 가능하며 모든 클래스의 정보 확인 가능

- 사용 이유)

  • 동적인 객체 생성
    • 런타임 시 클래스의 인스턴스를 동적으로 생성할 수 있음
    • 클래스 이름을 동적으로 전달하여 객체를 생성할 수 있으며, 유여한 객체 생성 패턴을 구현하는 데에 도움을 줌
  • 클래스 정보 조사
    • 클래스의 메서드, 필드, 상위 클래스, 인터페이스 등의 정보를 동적으로 조사할 수 있음
    • 이를 통해 프로그램이 실행 중에 클래스의 구조를 분석하고 다양한 작업을 수행할 수 있음
    • 특정 어노테이션을 가진 메서드를 찾거나, 클래스의 필드 값을 변경할 수 있음
  • 동적 메소드 호출
    • 메서드의 이름과 매개변수를 동적으로 지정하여 메소드를 호출할 수 있음
    • 일반적으로 알려지지 않은 클래스나 인터페이스와 상호작용해야 할 때 유용
    • 외부 라이브러리나 플러그인 시스템과의 통합에 활용할 수 있음
  • 에노테이션 처리
    • 에노테이션 정보를 읽고 처리할 수 있음
    • 런타임 시에 에노테이션을 분석하여 특정 작업을 수행하거나, 에노테이션을 기반으로 동적으로 코드를 생성할 수 있음
    • 프레임워크나 라이브러리에서 커스텀 에노테이션을 활용하여 기능을 활장하거나, 실행 중인 설정 정보를 처리하는 데 사용
  • 리소스 접근
    • 클래스 로더를 통해 리소스에 접근할 수 있음
    • 클래스 경로에 있는 파일이나 설정 파일 등을 동적으로 로드하여 사용할 수 있음

 

Class 클래스

: Class 클래스는 java.lang 패키지에서 제공되는 실행 중인 자바 어플리케이션의 클래스와 인터페이스의 정보를 가진 클래스

- public 생성자가 존재하지 않음

Class 객체는 JVM에 의해 자동으로 생성

 

1. Class의 기능

  • 클래스에 붙은 어노테이션 조회
  • 클래스 생성자 조회
  • 클래스 필드 조회
  • 클래스 메서드 조회
  • 부모 클래스 인터페이스 조회

2. Class 객체 가져오기

  • {클래스 타입}.class -> Class<?> class = Cat.class;
  • {인스턴스}.getClass() -> Cat 댕이 = new Cat("댕이");
                                            Class<?> class = 댕이.getClass();
  • Class.forName("{전체 도메인 이름}") -> Class<?> class = Class.forName("org.example.Cat");

cf) getMethods vs getDeclaredMethods

  • getMethods : 상위 클래스와 상위 인터페이스에서 상속한 메서드를 포함하여 public인 메서드들을 모두 가져옴
  • getDeclaredMethods : 접근 제어자와 관계없이 상속한 메소드를 제외하고 직접 클래스에서 선언한 메서드들을 모두 가져옴

cf) invoke()

: 메서드 객체를 호출하여 실행시킴

- 멀티스레드 환경에서는 데이터 보호를 위해 invoke를 사용함

  • 응용 프로그램이 실행될 때, 기본적으로 하나의 스레드가 발생
  • 이것을 Main() 스레드라고 부름 -> Main() 함수가 이 스레드의 시작점
  • Main 스레드가 메인 폼의 이벤트 처리를 담당하면서 메인 폼의 각종 컨트롤들의 값을 읽고 쓰는 작업을 수행
  • 메인 폼에서 다른 폼을 띄울 경우에도 기본적으로 메인 스레드가 자식 폼의 컨트롤들까지 모두 소유
  • 별도의 스레드에서 폼의 컨트롤을 엑세스하면 데이터가 깨질 수 있음
  • 별도의 스레드는 메인 스레드에게 컨트롤을 읽고 쓰는 작업을 위임하여 수행하게 햄
  • So, 외부 스레드가 메인 폼의 invoke를 호출

- Reflection은 v.invoke(s, o)

-> 클래스를 불러오고, 생성자를 구하고, 생성자에 인자를 넘겨 생성자를 만들고 메소드를 얻어와서 invoke() 함수로 실행하는 과정을 거침

 

Reflection을 사용하는 곳

- 프레임워크나 라이브러리에서 주로 사용

  • JPA
  • Jackson
  • Mockito
  • Intellij 자동 완성 기능

기본 생성자가 필요한 이유

- JPA Entity, RequestDTO, ResponseDTO 는 기본 생성자를 필요로 함

- Reflection으로 객체를 생성할 수 있고, 생성자가 있는데 왜 기본 생성자가 필요할까 ?

=> 기본 생성자로 객체를 생성하고, 필드를 통해 값을 넣어주는 것이 가장 간단한 방법이기 때문

 

어노테이션 작동법

  1. Reflection을 통해 클래스나 메서드, 파라미터 정보를 가져옴
  2. Reflection의 getAnnotation(s), getDeclaredAnnotation(s)등의 메서드를 통해 원하는 어노테이션이 붙어있는지 확인
  3. 어노테이션이 붙어있다면 원하는 로직을 수행

 

 

 

 

 

 

 

 

 

 

Reference

https://cartiertk.tistory.com/67

 

 

'JAVA' 카테고리의 다른 글

19. HashMap  (0) 2025.04.29
18. Collection Framework(List, Map, Set...)  (0) 2025.04.29
16. Generic  (1) 2025.04.29
15. Default Method & 추상 클래스 & 인터페이스  (0) 2025.04.29
14. Lambda & Functional Interface  (0) 2025.04.17