[리플렉션] 멤버의 취득과 조작

icehugger·2026년 4월 24일

training

목록 보기
8/8

① 기술적 정의 (Technical Definition)

자바 리플렉션 API는 실행 중인 자바 애플리케이션이 자신의 내부 구조를 검사하고, 클래스의 멤버(생성자, 필드, 메소드)를 동적으로 조작할 수 있게 해주는 기능입니다.

자바 명세상 리플렉션은 컴파일 시점에 알 수 없었던 클래스나 멤버에 접근하여 호출하거나 값을 변경하는 것을 허용합니다. 이는 정적 언어인 자바에 동적(Dynamic) 특성을 부여하며, 주로 프레임워크(Spring, JUnit 등)나 라이브러리 제작에 필수적으로 사용됩니다.

② 주요 메소드 및 키워드 (API Reference)

멤버를 취득할 때는 'Public만 가져올 것인가' 아니면 '선언된 모든 멤버를 가져올 것인가'에 따라 메소드가 나뉩니다.

・setAccessible(boolean flag): private 멤버에 접근하기 위해 반드시 true로 설정해야 하는 핵심 메소드입니다.

③ 메모리 및 실행 흐름 (Execution Flow)

리플렉션을 통한 멤버 조작은 일반적인 객체 접근보다 복잡한 단계를 거칩니다.

1.객체 확인: 힙(Heap) 메모리에 있는 대상 인스턴스의 Class 정보를 참조합니다.

2.메타데이터 검색: 메소드 영역(Method Area)에 저장된 클래스 구조 정보에서 요청한 이름과 일치하는 Field나 Method 객체를 생성하여 반환합니다.

3.권한 체크: 해당 멤버의 접근 제어자(private 등)를 확인합니다. 리플렉션 사용 시 이 단계를 우회하기 위해 setAccessible(true)를 호출하면 JVM의 보안 검사를 일시적으로 통과합니다.

4.실행/수정: * 필드: 힙 메모리에 있는 실제 인스턴스의 특정 메모리 주소 값을 직접 수정합니다.

・메소드: 바이트코드를 실행하기 위해 해당 메소드의 시작 주소로 점프하여 로직을 수행합니다.

④ 실제 구현 예제 (Implementation Example)

회사 연수 중에 가끔 "private 변수인데 강제로 값을 바꿔야 하거나, 메소드 이름을 문자열로 받아서 실행해야 하는 상황"을 가정해 보겠습니다.

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class User {
    private String name = "Default";
    private void sayHello() { System.out.println("Hello, " + name); }
}

public class ReflectionMemberTest {
    public static void main(String[] args) throws Exception {
        User user = new User();
        Class<?> clazz = user.getClass();

        // 1. private 필드 취득 및 수정
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true); // private 벽 허물기
        nameField.set(user, "HyunWook"); // 값 변경

        // 2. private 메소드 취득 및 실행
        Method helloMethod = clazz.getDeclaredMethod("sayHello");
        helloMethod.setAccessible(true);
        helloMethod.invoke(user); // "Hello, HyunWook" 출력
    }
}

⑤ 주의사항 및 디버깅 팁

1.성능 저하 (Overhead): 리플렉션은 JVM의 최적화(JIT 컴파일러)를 방해합니다. 일반적인 메소드 호출보다 수십 배 느릴 수 있으므로, 성능이 중요한 반복문 안에서는 사용을 피해야 합니다.

2.보안 및 캡슐화 파괴: private 멤버를 강제로 조작하는 것은 객체 지향의 원칙을 깨뜨리는 행위입니다. 클래스 내부 구조가 바뀌면 리플렉션 코드는 즉시 깨지므로 유지보수가 어렵습니다.

3.컴파일 시점 타입 체크 불가: 존재하지 않는 필드 이름을 문자열로 적어도 컴파일 에러가 나지 않습니다. 대신 실행 시점에 NoSuchFieldException이나 NoSuchMethodException이 발생하므로 반드시 예외 처리가 필요합니다.

4.디버깅 팁: 리플렉션 코드에서 에러가 발생하면 스택 트레이스가 매우 길어집니다. InvocationTargetException이 발생했다면, 이는 리플렉션 자체의 문제가 아니라 호출된 실제 메소드 내부에서 에러가 난 것이므로 getCause()를 통해 실제 원인을 확인해야 합니다.

0개의 댓글