1. 리플렉션이란
리플렉션이란 구체적인 클래스 타입을 알지 못해도 그 클래스의 메서드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API입니다.
컴파일 시간이 아닌 런타임 시간에 동적으로 특정 클래스의 정보를 추출할 수 있는 프로그래밍 기법이라고 할 수 있습니다.
2. 언제 사용
- 동적으로 클래스를 사용해야 할 때 사용합니다.
- 다시말해, 작성 시점에는 어떠한 클래스를 사용해야 할지 모르지만, 런타임 시점에서 가져와 실행해야하는 경우에 사용됩니다.
- 프레임워크나 IDE에서 이러한 동적 바인딩을 이용한 기능을 제공합니다.
2.1. 리플렉션 사용 예시
- Intellij 의 자동 완성 기능

- 스프링 어노테이션
- 스프링 어노테이션에서 리플렉션을 적용하는 방법은 추후 추가할 예정입니다.
3. 리플렉션을 사용하여 가져올 수 있는 정보
리플렉션을 통해 가져올 수 있는 정보는 다음과 같습니다.
- Class
- Constructor
- Method
- Field
4. 리플렉션을 사용하여 정보를 가져오는 법
이제 어떻게 리플렉션이 작동하는 지, 리플렉션을 사용하여 정보를 가져오는 방법에 대해 알아보도록 하겠습니다.
우선 다음과 같은 클래스가 있습니다.
<java />
public class Dog {
public String name = "snoopy";
public String color = "white";
// 기본 생성자
public Dog() {
}
public Dog(String name) {
this.name = name;
}
public void bark() {
System.out.println("Arf");
}
public String getName() {
return name;
}
public String getColor() {
return color;
}
public void setName(String name) {
this.name = name;
}
public void setColor(String color) {
this.color = color;
}
}
4.1. 클래스 이름 불러오기
<java />
Class clazz = Dog.class;
System.out.println("Class name: "+clazz.getName());
// Class name: _reflection.Dog
여기서 _reflection은 패키지 명입니다.
4.2. 이름으로 클래스 가져오기
반대로 이름을 통해서 클래스를 가져올 수도 있습니다.
<java />
Class clazz = Class.forName("_reflection.Dog");
System.out.println("Class name: "+clazz.getName());
// Class name: _reflection.Dog
4.3. 생성자 불러오기
.getDeclaredConstructor(); 는 인자없는 생성자를 가져옵니다.
<java />
Class clazz = Dog.class;
System.out.println("생성자: " + clazz.getDeclaredConstructor());
// 생성자: public _reflection.Dog()
만약, 파라미터를 넣으면( .getDeclaredConstructor(Param) ) 그 타입과 일치하는 생성자를 찾습니다.
<java />
Class clazz = Dog.class;
System.out.println("생성자: " + clazz.getDeclaredConstructor(String.class));
// 생성자: public _reflection.Dog(java.lang.String)
4.4. 메서드 불러오기
<java />
Class clazz = Dog.class;
System.out.println("메서드: " + clazz.getDeclaredMethod("bark"));
// 메서드: public void _reflection.Dog.bark()
4.5. 변수 불러오기
<java />
Class clazz = Dog.class;
System.out.println("변수명: " + clazz.getDeclaredField("name"));
// 변수명: public java.lang.String _reflection.Dog.name
4.6. 변수의 값 불러오기 및 변경하기
변수 값을 변경하는 방법은 여러가지가 있습니다.
필드명으로 변경하기
<java />
public class Main {
public static void main(String[] args) throws Exception {
Dog dog = new Dog();
Class clazz = Dog.class;
// 변수의 값 불러오기 및 변경하기
Field field = clazz.getDeclaredField("name");
System.out.println("변수값 변경 전: " + field.get(dog));
// 변수값: snoopy
field.set(dog, "pochacco");
System.out.println("변수값 변경 후: " + field.get(dog));
// 변수값 변경: pochacco
}
}
다음과 같이 field 명을 가져와서 해당 필드명을 이용하여 변경할 수 있습니다.
이 때 field.set을 이용할 때에는 객체와 변경할 변수를 함께 넣어주어야 합니다.
또한, 런타임 환경에서 이루어지기 때문에 만약에 변수 타입을 일치시키지 않는다면 다음과 같이 에러가 발생하게 됩니다.
<java />
field.set(dog, 123);

필드 리스트로 변경하기
리플렉션을 이용하면 .getDeclaredField(); 메서드를 통해 Field의 리스트도 가져올 수 있습니다.
이 때 필드의 순서는 해당 클래스에 선언한 순서입니다.
<java />
Class clazz = Dog.class;
Field[] field = clazz.getDeclaredFields();
System.out.println(Arrays.toString(field));
// [public java.lang.String _reflection.Dog.name, public java.lang.String _reflection.Dog.color]
따라서 해당 필드 리스트를 이용하여 set() 메서드를 사용해서 객체의 변수를 변경할 수 있습니다.
<java />
public class Main {
public static void main(String[] args) throws Exception {
Class clazz = Dog.class;
Dog dog = new Dog();
Field[] field = clazz.getDeclaredFields();
System.out.println("변수값 변경 전: " + field[0].get(dog));
// 변수값 변경 전: snoopy
field[0].set(dog, "pochacco");
System.out.println("변수값 변경 후: " + field[0].get(dog));
// 변수값 변경 후: pochacco
}
}
5. 참고
- https://jeongkyun-it.tistory.com/225
- https://upperleaf.tistory.com/2
- https://velog.io/@ych0716/reflection
- https://codechacha.com/ko/reflection/
'Java > 자바와 Spring' 카테고리의 다른 글
[Java] 어노테이션(Annotation) 이란? (0) | 2024.05.09 |
---|---|
[Spring] AOP(Aspect Oriented Programming)이란? (0) | 2024.05.06 |
[Java] 가비지 컬렉션이란 ? (0) | 2024.05.04 |
[Java] Synchronized 동기화란 (0) | 2024.05.02 |
[자바 ORM 표준 JPA 프로그래밍 - 기본편] 0-1. JPA란? (0) | 2023.12.15 |