반응형
Reflection(리플렉션)
- 클래스의 실체가 아닌 반사된 모습을 이용한 기능.
- Class 를 이용
- 리플렉션 기능을 지원하지 않는 언어 : C, C++. Pascal
- 사용되는 기술 : JPA, Jackson, Mockito, Junit ...
- 장점
- 외부, 사용자 정의 클래스들을 사용할 수 있게 함
- 접근제어자에 관계없이 접근이 가능하도록 함
- 단점
- 컴파일 시점이 아닌, 런타임 시점에 클래스를 분석
JVM을 최적화할 수 없어 성능저하 - 마찬가지로, 컴파일 에러 확인 불가
- 코드 가독성 저하
- 내부가 노출되어 추상화 파괴
- 컴파일 시점이 아닌, 런타임 시점에 클래스를 분석
Class
- 실행중인 자바 어플리케이션의 클래스와 인터페이스의 정보를 가진 클래스
- 클래스와 인터페이스의 정보를 가지고 있기 때문에, Class는 클래스의 내용을 모두 확인 가능
(ex, 어노테이션, 생성자, 필드, 메서드, 부모 클래스 등) - public 생성자가 존재하지 않고, JVM에 의해 자동으로 생성
- 메서드에 Declared 가 붙어있는 경우, 접근제어자 관계없이 해당 클래스에서 직접 관여한 부분을 조회
- getMethods() : public 메서드에 한해서 부모 클래스와 부모 인터페이스에서 상속한 메서드를 포함하여 조회
getDeclaredMethods() : 접근 제어자 관계없이 상속한 메서드를 제외하고 해당 클래스에서 직접 선언한 메서드를 조
- getMethods() : public 메서드에 한해서 부모 클래스와 부모 인터페이스에서 상속한 메서드를 포함하여 조회
Class 사용 방법
Person.java
package com.java8.other.reflection;
public class Person {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void privatePrint() {
System.out.println("privatePrint : " + toString());
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1) Class 가져오기
// 1. {클래스 이름}.class
Class<?> clazz1 = Person.class;
// 2. {인스턴스}.getClass()
Person person = new Person("김멍목", 28);
Class<?> clazz2 = person.getClass();
// 3.Class.forName("클래스 주소")
Class<?> clazz3 = Class.forName("com.java8.other.reflection.Person");
2) 생성자를 가져와서 인스턴스 만들기
.getConstructor() 를 이용해서 생성자를 가져올 수 있으며, 파라미터에 따라 생성자를 구분 가능
Constructor<?> declaredConstructor1 = clazz2.getDeclaredConstructor();
Constructor<?> declaredConstructor2 = clazz2.getDeclaredConstructor(String.class, int.class);
Object instance = declaredConstructor2.newInstance("멍목2", 7); // 방금 알아낸 생성자로 인스턴스 생성
System.out.println(instance.toString());
3) 접근제어자 무시하고 메서드 호출하기
Person person = new Person("김멍목", 28);
Class<?> clazz2 = person.getClass();
Method method = clazz2.getDeclaredMethod("privatePrint");
method.setAccessible(true); // 접근제어자 신경쓰지 않겠다.
System.out.println(method.getName());
method.invoke(person); // 해당 메서드 실행
※ Entity, Request/Response DTO 에 기본 생성자가 필요한 이유
- 리플렉션으로 기본 생성자를 가져와 인스턴스를 생성하고, 필드를 가져와서 값을 주입해주는 것이 간단하기 때문
- 여러 생성자가 있을 경우, 간단하게 파라미터 타입이나 갯수를 신경쓰지 않고 기본 생성자로 객체 생성
※ Annotation은 주석인데 작동하는 이유
- 리플렉션으로 getAnnotation(s)를 통해 해당 클래스에 어노테이션이 있는 지 확인
Reference
반응형
'BE > Java' 카테고리의 다른 글
[Java 8] Stream, 데이터 리듀싱 (1) | 2024.03.24 |
---|---|
[Java 8] 람다식과 함수형 인터페이스 (0) | 2024.03.10 |
[Java] Jacoco 간단하게 사용해보기 (Maven) (0) | 2023.07.08 |
[Mockito] ArgumentCaptor (0) | 2023.05.29 |
[Java 8] Annotation, sort, Metaspace (0) | 2023.05.04 |