본문 바로가기
(2024-10) 스파르타 내일배움캠프 - 백엔드/Java Reflect

예시로 함께 보는 Reflect와 Constructor(1)

by 어뫄어뫄 2024. 11. 26.

아래 예제는 Java Reflection을 사용하여 두 요소를 실습합니다.:

  1. 생성자 탐색:
    • 클래스의 생성자 목록을 동적으로 가져오고 출력합니다.
  2. 객체 동적 생성:
    • 제공된 인자에 따라 적합한 생성자를 선택하여 객체를 동적으로 생성합니다.

--------------------------

 

 

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 +
                    '}';
        }
    }
}

 

 

주요 구성 요소

  1. displayConstructorDetails:
    • clazz.getDeclaredConstructors()를 사용하여 클래스의 모든 생성자를 가져옵니다.
    • 각 생성자의 매개변수 유형을 출력합니다.
    예시: Car 클래스의 생성자 정보 출력
  2. 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을 인자로 객체를 생성합니다.
  3. 동적 동작:
    • 코드를 직접 수정하지 않고도 생성자를 동적으로 호출할 수 있어 유연하고 재사용 가능한 기능을 제공합니다.
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);
  • 용도:
    • 동적으로 객체를 생성할 때 사용.
    • 런타임 시 매개변수를 기반으로 객체를 유연하게 생성.