Files
java-examples/docs/Reflection.md

196 lines
6.9 KiB
Markdown

# **자바 리플렉션(Reflection) 쉽게 배우기**
## **1. 리플렉션이란?**
리플렉션(Reflection)이란 **실행 중에 클래스의 정보를 조회하고, 필드·메서드·생성자를 동적으로 조작하는 기능**이다.
즉, **컴파일 시점이 아니라 런타임(실행 중)에 클래스 내부를 들여다보고 조작할 수 있다.**
---
## **2. 주요 클래스 및 메서드 정리**
### **(1) `Class` 클래스 (클래스 정보 조회)**
| 메서드 | 설명 |
|-----|---|
| `Class.forName("클래스명")` | 클래스 객체 가져오기 (정적 로드) |
| `Object.getClass()` | 인스턴스로부터 클래스 객체 얻기 |
| `getName()` | 클래스 전체 이름 (`패키지.클래스명`) 반환 |
| `getSimpleName()` | 클래스 단순 이름 반환 |
| `getDeclaredFields()` | 선언된 모든 필드(`Field[]`) 조회 |
| `getDeclaredMethods()` | 선언된 모든 메서드(`Method[]`) 조회 |
| `getDeclaredConstructors()` | 선언된 모든 생성자(`Constructor[]`) 조회 |
**예제 코드 (클래스 정보 출력)**
```java
Class<?> clazz = Class.forName("java.util.ArrayList");
System.out.println("클래스 이름: " + clazz.getName());
System.out.println("간단한 이름: " + clazz.getSimpleName());
System.out.println("패키지: " + clazz.getPackage().getName());
```
**클래스의 이름과 패키지 정보를 확인할 수 있다!**
---
### **(2) `Field` 클래스 (필드 정보 조회 및 수정)**
| 메서드 | 설명 |
|-----|---|
| `getName()` | 필드 이름 가져오기 |
| `getType()` | 필드 타입 가져오기 |
| `getModifiers()` | 접근 제어자 가져오기 |
| `setAccessible(true)` | private 필드 접근 가능하게 설정 |
| `get(Object obj)` | 특정 객체의 필드 값 가져오기 |
| `set(Object obj, Object value)` | 특정 객체의 필드 값 변경 |
**예제 코드 (필드 조회 및 값 변경)**
```java
import java.lang.reflect.*;
class Person {
private String name = "John";
}
public class ReflectionExample {
public static void main(String[] args) throws Exception {
Person person = new Person();
Class<?> clazz = person.getClass();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true); // private 접근 허용
System.out.println("기존 값: " + field.get(person));
field.set(person, "Alice"); // 값 변경
System.out.println("변경된 값: " + field.get(person));
}
}
```
**private 필드도 강제로 조작할 수 있다!**
---
### **(3) `Method` 클래스 (메서드 정보 조회 및 호출)**
| 메서드 | 설명 |
|-----|---|
| `getName()` | 메서드 이름 가져오기 |
| `getParameterTypes()` | 메서드 매개변수 타입 가져오기 |
| `getReturnType()` | 반환 타입 가져오기 |
| `invoke(Object obj, Object... args)` | 메서드 실행 |
**예제 코드 (메서드 실행)**
```java
import java.lang.reflect.*;
class Calculator {
private int add(int a, int b) {
return a + b;
}
}
public class ReflectionExample {
public static void main(String[] args) throws Exception {
Calculator calc = new Calculator();
Class<?> clazz = calc.getClass();
Method method = clazz.getDeclaredMethod("add", int.class, int.class);
method.setAccessible(true); // private 접근 허용
int result = (int) method.invoke(calc, 5, 10); // 메서드 실행
System.out.println("결과: " + result);
}
}
```
**private 메서드도 실행할 수 있다!**
---
### **(4) `Constructor` 클래스 (생성자 정보 조회 및 인스턴스 생성)**
| 메서드 | 설명 |
|-----|---|
| `getParameterTypes()` | 생성자 매개변수 타입 가져오기 |
| `newInstance(Object... initargs)` | 새로운 인스턴스 생성 |
**예제 코드 (객체 동적 생성)**
```java
import java.lang.reflect.*;
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class ReflectionExample {
public static void main(String[] args) throws Exception {
Class<?> clazz = Person.class;
Constructor<?> constructor = clazz.getConstructor(String.class);
Object person = constructor.newInstance("Charlie"); // 동적 생성
Method method = clazz.getMethod("getName");
System.out.println("이름: " + method.invoke(person)); // Charlie 출력
}
}
```
**리플렉션을 이용해 생성자를 실행하고 객체를 만들 수 있다!**
---
### **(5) `Modifier` 클래스 (접근 제어자 확인)**
| 메서드 | 설명 |
|-----|---|
| `isPublic(int mod)` | public 여부 확인 |
| `isPrivate(int mod)` | private 여부 확인 |
| `isStatic(int mod)` | static 여부 확인 |
**예제 코드 (필드 접근 제어자 확인)**
```java
import java.lang.reflect.*;
class Sample {
private int num;
public static String text;
}
public class ReflectionExample {
public static void main(String[] args) throws Exception {
Field field = Sample.class.getDeclaredField("text");
int modifiers = field.getModifiers();
System.out.println("static인가? " + Modifier.isStatic(modifiers)); // true
System.out.println("public인가? " + Modifier.isPublic(modifiers)); // true
}
}
```
**필드나 메서드가 `public`, `private`, `static`인지 확인할 수 있다!**
---
## **3. 리플렉션의 활용 예시**
**DI(의존성 주입) 프레임워크(Spring)** → 리플렉션으로 객체를 생성하고 자동 주입
**JUnit 테스트 프레임워크**`@Test` 붙은 메서드 자동 실행
**JSON 라이브러리(Jackson, Gson)** → 객체를 JSON으로 변환할 때 필드 조회
**프록시 패턴(AOP, 동적 프록시)** → 런타임에 동적 메서드 실행
---
## **4. 리플렉션의 단점과 주의점**
**성능 저하** → 리플렉션은 일반 메서드 호출보다 느리다. 자주 사용하면 성능 문제가 생길 수 있다.
**보안 문제**`setAccessible(true)`로 private 필드/메서드에 접근할 수 있어 보안 위험이 있다.
**컴파일 타임 체크 불가능** → 오타나 잘못된 메서드 호출은 실행 시점에서야 오류가 발생한다.
**따라서, 꼭 필요한 경우에만 사용하고 남용하지 않는 것이 좋다!**
---
## **5. 정리**
**리플렉션은 실행 중 클래스 정보를 조회하고 조작할 수 있는 기능이다!**
**`Class`, `Field`, `Method`, `Constructor` 클래스를 활용하면 필드 값 변경, 메서드 실행, 객체 생성 등이 가능하다!**
**Spring, JSON 파싱, 테스트 프레임워크 등에서 널리 사용된다!**
**하지만 성능 저하와 보안 문제를 고려하여 신중히 사용해야 한다!**
✔ **리플렉션을 잘 활용하면, 자바 프로그램을 더 유연하게 만들 수 있다!**