공개 글

Reflection과 Class 객체

영발개발 2025. 7. 31. 13:53

Reflection에 대해 쓰기 전에 먼저 Class 객체에 대해서 먼저 정리해보자.


Class 객체

 

정의
  •  Class는 모든 자바 클래스의 '메타데이터(설계도)'를 담는 그릇
  •  일반 객체(new Person())는 실제 사람 인스턴스
  •  Class<Person>은 사람이라는 설계도 자체

 

왜 Class<?>를 쓰는가?

 어떤 클래스가 올지 모를때 사용한다.

(추가로, 어떤 객체가 올지 모를때 사용된다는 점은 비슷하지만 Object는 실제 객체를 담는 것이고, Class는 클래스의 메타데이터를 담는다.)

 

Object obj = new Person(); // 실제 Person 객체가 들어감
			
Class<?> clazz = Person.class;   // Person의 설계도
Object obj = clazz.getDeclaredConstructor().newInstance(); // 설계도로 객체 생성

 

 

실제 프로젝트에서 봤던 코드
Class<?> clazz = vo.getClass();
Field[] fields = clazz.getDeclaredFields();

여기서 나오는 '.getDeclaredFields()'는 Class<?> 객체가 가진 모든 필드(멤버 변수)를 Field 객체 배열로 반환하는 메서드다.

 

예를 들어,

class Person {
	private String name;
	public int age;
}

public class FieldDetailExample {
	public static void main(String[] args) throws Exception {
		Class<?> clazz = Person.class;
		Field[] fields = clazz.getDeclaredFields();
        
		for (Field field : fields) {
			System.out.println("toString(): " + field);  // Field 객체의 문자열 표현
			System.out.println("이름: " + field.getName());
			System.out.println("타입: " + field.getType());
			System.out.println("접근제어자: " + java.lang.reflect.Modifier.toString(field.getModifiers()));
			System.out.println("------");
		}
	}
}

위와 같이 코딩하면,

 

toString(): private java.lang.String Person.name
이름: name
타입: class java.lang.String
접근제어자: private
------
toString(): public int Person.age
이름: age
타입: int
접근제어자: public
------

이런 식으로 객체의 멤버 변수(필드) 하나하나의 정보를 담은 객체가 출력되는 걸 확인 할 수 있다.

 


Reflection

 

정의

 Java에서 제공하는 표준 API로, 런타임에 클래스, 메서드, 필드, 생성자 등에 접근하고 조작할 수 있는 기능이다.

 

- 중요 포인트

  • 컴파일 시점이 아니라 프로그램 실행 중(런타임)에 클래스의 구조를 읽고 조작
  • 클래스 이름, 어노테이션, 메서드 시그니처 등을 문자열로 찾아 동적으로 로직 실행 가능
더보기

** 컴파일(Compile-time)과 런타임(Runtime) 차이

 

[소스코드] --(컴파일)--> [바이트코드(.class)] --(실행)--> [런타임: JVM 메모리 위에서 동작]

- 컴파일:
javac가 .java → .class(바이트코드)로 변환
문법 검사 + 타입 체크만 함
클래스가 실제로 실행되거나 메모리에 올라오진 않음

- 런타임:
java로 JVM이 .class를 읽어서 메모리에 로드
메서드 호출, 객체 생성, 변수 값 변경 등 실제 동작이 이루어짐
Reflection은 이 시점에서 클래스 정보를 읽어옴

 

코드로 보는 차이

<일반 호출(컴파일 시점에 확정)>

Person p = new Person(); // 컴파일러가 Person 클래스 존재 확인
p.sayHello();           // 메서드 존재 여부도 컴파일 시점에 체크됨

 

<Reflection 호출 (런타임에만 검사됨)>

Class<?> clazz = Class.forName("Person");   // 문자열 기반 → 컴파일러는 확인 못함
Object obj = clazz.getDeclaredConstructor().newInstance();
Method m = clazz.getMethod("sayHello");     // 없는 메서드면 여기서 런타임 예외
m.invoke(obj);