리플렉션으로 필드도 탐색할 수 있다. 메서드랑 비슷하게 getFields와 getDeclaredFileds로 필드들을 가져오고 필드 배열 만들어 주면 된다. 필드 값도 변경해줄 수 있는데
import java.lang.reflect.Field;
// 값을 변경할 대상 클래스
class User {
private String name;
public User(String name) {
this.name = name;
}
@Override
public String toString() {
return "User[name=" + this.name + "]";
}
}
// 리플렉션을 실행하는 메인 클래스
public class FieldSetExample {
public static void main(String[] args) throws Exception {
// 1. 값을 변경할 객체 생성
User user = new User("김철수");
System.out.println("변경 전: " + user);
// 2. 클래스에서 'name'이라는 이름의 필드 정보를 찾아옴
Field nameField = User.class.getDeclaredField("name");
// 3. private 필드에 접근할 수 있도록 권한 설정 (필수)
nameField.setAccessible(true);
// 4. set()을 이용해 필드 값 변경 🎯
nameField.set(user, "박영희");
// 5. 결과 확인
System.out.println("변경 후: " + user);
}
}
이런 방식으로 set을 통해 간편하게 바꿀 수 있다. 여기서도 setAccessible을 통해 private에 접근하고 변경할 수 있다. 다만, 직접 접근하기보다는 getter나 setter로 접근하는 게 좋다.
import java.lang.reflect.Constructor;
// 다양한 접근 제어자를 가진 생성자가 있는 클래스
class User {
// Public 생성자
public User() {}
public User(String name) {}
// Protected 생성자
protected User(String name, int age) {}
// Private 생성자
private User(long id) {}
}
// 리플렉션으로 생성자를 탐색하는 메인 클래스
public class ConstructorSearchExample {
public static void main(String[] args) {
Class<?> userClass = User.class;
// 1. getConstructors(): public 생성자만 가져옴
System.out.println("--- getConstructors() 결과 (public만) ---");
Constructor<?>[] publicConstructors = userClass.getConstructors();
for (Constructor<?> constructor : publicConstructors) {
System.out.println(constructor);
}
System.out.println(); // 줄바꿈
// 2. getDeclaredConstructors(): 모든 접근 제어자의 생성자를 가져옴
System.out.println("--- getDeclaredConstructors() 결과 (모두) ---");
Constructor<?>[] allConstructors = userClass.getDeclaredConstructors();
for (Constructor<?> constructor : allConstructors) {
System.out.println(constructor);
}
}
}
생성자도 이런 방식으로 조회할 수 있다. 참고로 메서드, 필드와는 다르게 getConstructors는 해당 클래스의 public 생성자만, getDeclaredConstructors는 해당 클래스의 모든 생성자를 조회한다. 생성자는 부모 클래스로부터 상속받지 않기 때문이다.
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
// 대상 클래스
class Greeter {
private final String greetingMessage;
// String을 받는 public 생성자
public Greeter(String greetingMessage) {
this.greetingMessage = greetingMessage;
}
// 호출할 메서드
public void sayHello(String name) {
System.out.println(this.greetingMessage + ", " + name + "!");
}
}
// 리플렉션 실행 클래스
public class FullFlowExample {
public static void main(String[] args) throws Exception {
// --- 1. 생성자 조회 ---
// String 타입 파라미터를 받는 생성자 정보를 가져옴
Constructor<Greeter> constructor = Greeter.class.getConstructor(String.class);
// --- 2. newInstance()로 인스턴스 생성 ---
// 조회한 생성자를 이용해 "안녕하세요"라는 초기값을 주며 인스턴스를 만듦
Greeter greeterInstance = constructor.newInstance("안녕하세요");
// --- 3. 메서드 조회 및 호출 ---
// 호출할 메서드(sayHello) 정보를 가져옴
Method sayHelloMethod = Greeter.class.getMethod("sayHello", String.class);
// 위에서 만든 인스턴스(greeterInstance)를 이용해 메서드를 호출함
sayHelloMethod.invoke(greeterInstance, "홍길동");
}
}
이렇게 하면 생성자 조회한 걸 통해 바로 인스턴스를 만들고 그 인스턴스를 이용해 메서드까지 호출할 수 있다.