Constructor(생성자) 제어
이 문서에서는 Java Reflection을 이용하여 생성자 정보를 얻어내고 객체를 생성하는 방법을 다룬다.
클래스의 형태
예제에서 사용할 클래스의 형태는 다음과 같다. 다양한 생성자를 추가해두었고, 접근제한 확인을 위해 기본생성자를 private 처리해두었다.
package com.hacademy.reflection5;
public class Product {
private String name;
private String type;
private int price;
private Product() {
this("미설정", "없음", 0);
}
public Product(String name) {
this(name, "없음", 0);
}
public Product(String name, String type) {
this(name, type, 0);
}
public Product(String name, String type, int price) {
this.name = name;
this.type = type;
this.price = price;
}
@Override
public String toString() {
return "Product [name=" + name + ", type=" + type + ", price=" + price + "]";
}
}
예제 - 생성자 목록 불러오기
package com.hacademy.reflection5;
import java.lang.reflect.Constructor;
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName("com.hacademy.reflection5.Product");
System.out.println("<Accessible constructor list>");
for(Constructor<?> constructor : c.getConstructors()) {
System.out.println(constructor);
}
System.out.println("<Declared constructor list>");
for(Constructor<?> constructor : c.getDeclaredConstructors()) {
System.out.println(constructor);
}
}
}
생성자 목록을 조회할 수 있는 명령은 두 가지가 있다.
class.getConstructors()
- 접근 가능한 생성자 목록을 조회
class.getDeclaredConstructors()
- 모든 생성자 목록을 조회
예제 - 생성자를 정하여 불러오기
package com.hacademy.reflection5;
import java.lang.reflect.Constructor;
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
Class<?> c = Class.forName("com.hacademy.reflection5.Product");
//Constructor<?> c1 = c.getConstructor();//error
Constructor<?> c2 = c.getConstructor(String.class);
Constructor<?> c3 = c.getConstructor(String.class, String.class);
Constructor<?> c4 = c.getConstructor(String.class, String.class, int.class);
Constructor<?> c5 = c.getDeclaredConstructor();
Constructor<?> c6 = c.getDeclaredConstructor(String.class);
Constructor<?> c7 = c.getDeclaredConstructor(String.class, String.class);
Constructor<?> c8 = c.getDeclaredConstructor(String.class, String.class, int.class);
System.out.println("c2 = " + c2);
System.out.println("c3 = " + c3);
System.out.println("c4 = " + c4);
System.out.println("c5 = " + c5);
System.out.println("c6 = " + c6);
System.out.println("c7 = " + c7);
System.out.println("c8 = " + c8);
}
}
생성자를 불러올 때는 형태를 지정하여 불러온다. 다음 두 가지 명령이 존재한다.
class.getConstructor(형태)
- 접근 가능한 생성자 중 형태에 맞는 생성자 객체를 반환. 없으면 NoSuchMethodException 발생
class.getDeclaredConstructor(형태)
- 모든 생성자 중 형태에 맞는 생성자 객체를 반환. 없으면 NoSuchMethodException 발생
예제 - 기본 생성자를 이용한 객체 생성
package com.hacademy.reflection5;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> c = Class.forName("com.hacademy.reflection5.Product");
Constructor<?> constructor = c.getDeclaredConstructor();
constructor.setAccessible(true);
Product product = (Product) constructor.newInstance();
System.out.println(product);
}
}
생성자 객체에 있는 .newInstance()
메소드를 호출하면 인스턴스를 생성할 수 있다.
예제 클래스인 Product에서는 기본 생성자가 private이기 때문에 생성 전 .setAccessible(true)
설정이 필요하다.
constructor.setAccessible(true);
생성 시 인스턴스가 Object 형태로 반환되므로 생성한 형태에 맞게 Down-casting 해주어야 한다.
Product product = (Product) constructor.newInstance();
예제 - 매개변수 (String) 생성자 이용한 객체 생성
package com.hacademy.reflection5;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> c = Class.forName("com.hacademy.reflection5.Product");
Constructor<?> constructor = c.getDeclaredConstructor(String.class);
Product product = (Product) constructor.newInstance("컴퓨터");
System.out.println(product);
}
}
이전 예제와 다른 점은 다음과 같다.
생성자가 접근 가능하므로 .setAccessible(true)
를 사용하지 않음
객체 생성 시 생성자 형태에 맞는 데이터 전달
예제 - 매개변수 (String, String) 생성자 이용한 객체 생성
package com.hacademy.reflection5;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> c = Class.forName("com.hacademy.reflection5.Product");
Constructor<?> constructor = c.getDeclaredConstructor(String.class, String.class);
Product product = (Product) constructor.newInstance("컴퓨터", "전자제품");
System.out.println(product);
}
}
예제 - 매개변수 (String, String, int) 생성자 이용한 객체 생성
package com.hacademy.reflection5;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test06 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> c = Class.forName("com.hacademy.reflection5.Product");
Constructor<?> constructor = c.getDeclaredConstructor(String.class, String.class, int.class);
Product product = (Product) constructor.newInstance("컴퓨터", "전자제품", 1500000);
System.out.println(product);
}
}