리플렉션이란?
- 구체적인 클래스 타입을 알지 못하더라도 그 클래스의 메서드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API를 말한다.
- 힙 영역에 로드된 Class 타입의 객체를 통해 클래스의 인스턴스를 생성할 수 있도록 지원하고, 인스턴스 필드와 메서드를 접근 제어자와 상관없이 사용할 수 있도록 지원한다.
리플렉션을 사용하는 경우
- 동적으로 클래스를 사용해야할 때
- 작성 시점에는 어떠한 클래스를 사용해야 할지 모르지만 런타임 시점에 가져와 실행해야 하는 경우
리플렉션으로 가져올 수 있는 정보
- Class
- Constructor
- Method
- Field
이제 reflection을 사용해보자!
Class 객체 획득 방법
- java.lang 패키지에서 제공
- Class 타입에 대한 instance는 Singleton이다
- 3가지 방법이 있다.
//방법 1
Worker worker = new Worker("test", Worker.POSITION_MANAGER); //일반적인 방식
Class cls1 = worker.getClass();
Class cls2 = Worker.class; //방법 2
//방법 3
Class cls3 = null;
try {
cls3 = Class.forName("oop21.reflection01.Worker"); //패키지 이름 적으면 됨
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("cls1.hashCode : " + cls1.hashCode());
System.out.println("cls2.hashCode : " + cls2.hashCode());
System.out.println("cls3.hashCode : " + cls3.hashCode());
실행결과를 보면 전부 다 같은 해시코드를 가지고 있는 것을 확인할 수 있다.
Constructor, Method, Field의 정보 가져오기
가져올 수 있는 방법에는 메서드를 getDeclaredXXX(), getXXX() 사용하는 방법이 있다.
1. 먼저 테스트할 클래스 Worker를 만든다.
public class Worker {
public static final int POSITION_MANAGER = 0;
public static final int POSITION_ASSISTANT = 1;
public static final int POSITION_EMPLOYEE = 2;
private String name;
private int position;
public Worker() {
name = null;
position = Integer.MAX_VALUE;
}
public Worker(String name, int position) {
super();
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
@Override
public String toString() {
return "Worker [name=" + name + ", position=" + position + "]";
}
}
2. getDeclaredXXX() 메서드를 사용하는 방법
public class ReflectionTest2 {
public static void main(String[] args) {
Class<?> cls = Worker.class;
// Constructor 타입의 객체를 배열로 얻어옴
// 지금은 생성자 2개 구현되어 있으니 2개를 배열로 얻어옴
Constructor<?>[] constructors = cls.getDeclaredConstructors();
System.out.println("=================== [생성자] ===================");
for(int i = 0; i<constructors.length; i++) {
System.out.println(constructors[i].toString());
}
System.out.println();
//method 정보 가져오기
Method[] methods = cls.getDeclaredMethods();
System.out.println("=================== [메서드] ===================");
for(int i = 0; i<methods.length; i++) {
System.out.println(methods[i].toString());
}
System.out.println();
//field 정보 가져오기
Field[] fields = cls.getDeclaredFields();
System.out.println("=================== [필드] ===================");
for(int i = 0; i<fields.length; i++) {
System.out.println(fields[i].toString());
}
}
}
결과를 보면 Worker 클래스에 정의한 생성자 2개, 메소드 5개, 필드 5개가 나오는 것을 확인할 수 있다.
3. getXXX() 메서드를 사용하는 방법
public class ReflectionTest3 {
public static void main(String[] args) {
Class<?> cls = Worker.class;
Constructor<?>[] constructors = cls.getConstructors();
System.out.println("=================== [생성자] ===================");
for(int i = 0; i<constructors.length; i++) {
System.out.println(constructors[i].toString());
}
System.out.println();
//method 정보 가져오기
Method[] methods = cls.getMethods();
System.out.println("=================== [메서드] ===================");
for(int i = 0; i<methods.length; i++) {
System.out.println(methods[i].toString());
}
System.out.println();
//field 정보 가져오기
Field[] fields = cls.getFields();
System.out.println("=================== [필드] ===================");
for(int i = 0; i<fields.length; i++) {
System.out.println(fields[i].toString());
}
}
}
getXXX() 메서드를 사용한 결과를 보면
메서드는 우리가 Worker 클래스에 정의한 method 이외에 Object 클래스로부터 상속받은 메서드 정보도 같이 나오는 것을 확인할 수 있다.
필드는 private으로 선언한 name과 position의 정보는 가져오지 못하는 것을 확인할 수 있다.
'Study' 카테고리의 다른 글
JDBC 이해 (0) | 2024.06.18 |
---|---|
[Spring Boot] Swagger 적용하기2 - Parameters & RequestBody (0) | 2023.08.05 |
[Spring Boot] Swagger 적용하기1 - controller & response (0) | 2023.08.03 |
[Spring boot + Swagger] Swagger 적용 (0) | 2023.08.03 |