아래 예제는 Java Reflection을 사용하여 두 요소를 실습합니다.:
- 생성자 탐색:
- 클래스의 생성자 목록을 동적으로 가져오고 출력합니다.
- 객체 동적 생성:
- 제공된 인자에 따라 적합한 생성자를 선택하여 객체를 동적으로 생성합니다.
--------------------------
package reflectexample;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
public class ReflectionDemo {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
displayConstructorDetails(Car.class);
Engine engine = createInstanceWithArguments(Engine.class, "V8", 450);
Car car = createInstanceWithArguments(Car.class, engine, "Red", 2023);
System.out.println(car);
}
public static <T> T createInstanceWithArguments(Class<T> clazz, Object... args)
throws IllegalAccessException, InvocationTargetException, InstantiationException {
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
if (constructor.getParameterCount() == args.length) {
return (T) constructor.newInstance(args);
}
}
System.out.println("No matching constructor found.");
return null;
}
public static void displayConstructorDetails(Class<?> clazz) {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
System.out.printf("Class %s has %d constructors:%n", clazz.getSimpleName(), constructors.length);
for (Constructor<?> constructor : constructors) {
String paramTypes = Arrays.toString(constructor.getParameterTypes());
System.out.printf("Constructor parameters: %s%n", paramTypes);
}
}
public static class Car {
private final Engine engine;
private final String color;
private final int year;
public Car() {
this.engine = null;
this.color = "Unknown";
this.year = 0;
}
public Car(String color, int year) {
this.engine = null;
this.color = color;
this.year = year;
}
public Car(Engine engine, String color, int year) {
this.engine = engine;
this.color = color;
this.year = year;
}
@Override
public String toString() {
return "Car{" +
"engine=" + engine +
", color='" + color + '\'' +
", year=" + year +
'}';
}
}
public static class Engine {
private final String type;
private final int horsepower;
public Engine(String type, int horsepower) {
this.type = type;
this.horsepower = horsepower;
}
@Override
public String toString() {
return "Engine{" +
"type='" + type + '\'' +
", horsepower=" + horsepower +
'}';
}
}
}
주요 구성 요소
- displayConstructorDetails:
- clazz.getDeclaredConstructors()를 사용하여 클래스의 모든 생성자를 가져옵니다.
- 각 생성자의 매개변수 유형을 출력합니다.
- createInstanceWithArguments:
- 클래스의 모든 생성자를 반복하며, 인자 수(constructor.getParameterCount())가 제공된 인자 수와 일치하는 생성자를 찾습니다.
- 일치하는 생성자를 찾으면 constructor.newInstance(args)를 사용하여 객체를 생성합니다.
- Engine 클래스의 생성자 Engine(String type, int horsepower)를 사용하여 "V8"과 450을 인자로 객체를 생성합니다.
- Car 클래스의 생성자 Car(Engine engine, String color, int year)를 사용하여 Engine 객체, "Red", 2023을 인자로 객체를 생성합니다.
- 동적 동작:
- 코드를 직접 수정하지 않고도 생성자를 동적으로 호출할 수 있어 유연하고 재사용 가능한 기능을 제공합니다.
Class Car has 3 constructors:
Constructor parameters: []
Constructor parameters: [class java.lang.String, int]
Constructor parameters: [class reflectexample.ReflectionDemo$Engine, class java.lang.String, int]
Class Car has 3 constructors:
Constructor parameters: []
Constructor parameters: [class java.lang.String, int]
Constructor parameters: [class reflectexample.ReflectionDemo$Engine, class java.lang.String, int]
Class Engine has 1 constructors:
Constructor parameters: [class java.lang.String, int]
Car{engine=Engine{type='V8', horsepower=450}, color='Red', year=2023}
<T>.class
- 설명: 특정 클래스의 Class 객체를 참조할 때 사용합니다.
- 역할: 런타임 시 클래스의 메타정보를 가져오기 위해 사용됩니다.
- 예시:
Class<String> stringClass = String.class; // String 클래스의 메타정보를 가져옴
- 용도:
- Reflection에서 클래스 정보를 탐색.
- 클래스 타입을 동적으로 다룰 때 활용.
Class<T>
- 설명: 제네릭을 사용하는 Class 타입으로, 특정 타입 T의 클래스를 표현합니다.
- 역할: 컴파일 시 타입 안정성을 제공합니다.
- 예시:
public static <T> void printClassName(Class<T> clazz) { System.out.println("Class name: " + clazz.getName()); } printClassName(String.class); // 출력: Class name: java.lang.String
- 용도:
- 제네릭과 함께 사용하여 Reflection 코드를 더 안전하게 작성.
- 클래스 타입을 동적으로 전달받아 작업 수행.
Constructor<?>
- 설명: 클래스의 생성자를 나타내는 Reflection 객체입니다.
- 역할: 특정 클래스의 생성자를 조작하거나 호출할 수 있습니다.
- 예시:
Constructor<String> constructor = String.class.getConstructor(String.class); String newString = constructor.newInstance("Hello"); System.out.println(newString); // 출력: Hello
- 특징:
- <?>는 생성자의 매개변수 타입에 상관없이 사용할 수 있음을 나타냄.
- getParameterTypes()를 통해 생성자의 매개변수 정보를 확인 가능.
- newInstance(args...)로 객체 생성 가능.
getDeclaredConstructors()
- 설명: 클래스의 모든 선언된 생성자를 반환하는 Reflection 메서드.
- 접근 제한자(private, public 등)에 관계없이 클래스에 선언된 모든 생성자를 반환.
- 상속된 생성자는 포함되지 않음.
- 반환값: Constructor<?>[] 배열 (모든 생성자의 배열).
- 예시:
Constructor<?>[] constructors = MyClass.class.getDeclaredConstructors(); System.out.println("생성자 개수: " + constructors.length); for (Constructor<?> constructor : constructors) { System.out.println(constructor); }
- 용도:
- 클래스의 모든 생성자 정보를 얻기 위해 사용.
- 동적 객체 생성 시 적합한 생성자를 찾기 위해 활용.
getParameterCount()
- 설명: 특정 생성자가 요구하는 매개변수의 개수를 반환하는 메서드.
- 반환값: int (매개변수의 개수).
- 예시:
Constructor<?>[] constructors = MyClass.class.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("매개변수 개수: " + constructor.getParameterCount()); }
- 용도:
- 생성자를 선택할 때 매개변수 개수에 따라 필터링 가능.
- Reflection으로 동적 객체를 생성하기 전, 적절한 생성자를 확인하는 데 유용.
newInstance()
- 설명: Reflection을 사용하여 생성자를 호출하고 객체를 생성하는 메서드.
- 특정 생성자에 맞는 인자를 전달하여 객체를 생성.
- 기본 생성자를 호출할 경우 인자가 필요 없음.
- 예외:
- IllegalAccessException: 생성자가 접근 제한자(private) 때문에 호출할 수 없을 때.
- InstantiationException: 추상 클래스나 인터페이스의 객체를 생성하려 할 때.
- InvocationTargetException: 생성자 호출 중 발생한 예외를 래핑한 예외.
- 예시:
Constructor<MyClass> constructor = MyClass.class.getDeclaredConstructor(String.class, int.class); MyClass obj = constructor.newInstance("Example", 42); System.out.println(obj);
- 용도:
- 동적으로 객체를 생성할 때 사용.
- 런타임 시 매개변수를 기반으로 객체를 유연하게 생성.
'(2024-10) 스파르타 내일배움캠프 - 백엔드 > Java Reflect' 카테고리의 다른 글
ConfigLoader 예제 (0) | 2024.11.27 |
---|---|
필드 제어 예제2) Json Serializer with Array (0) | 2024.11.27 |
Field 제어 (0) | 2024.11.27 |
Java Reflect의 Array 제어 (0) | 2024.11.27 |
Constructor 예제, 싱글턴에서(2) (0) | 2024.11.26 |