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으로 객체를 생성할 수 있고, 생성자가 있는데 왜 기본 생성자가 필요할까 ?
=> 기본 생성자로 객체를 생성하고, 필드를 통해 값을 넣어주는 것이 가장 간단한 방법이기 때문
어노테이션 작동법
- Reflection을 통해 클래스나 메서드, 파라미터 정보를 가져옴
- Reflection의 getAnnotation(s), getDeclaredAnnotation(s)등의 메서드를 통해 원하는 어노테이션이 붙어있는지 확인
- 어노테이션이 붙어있다면 원하는 로직을 수행
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 |