자바 리플렉션 (Reflection)이란?

CJI0524·2025년 2월 3일
0

Java

목록 보기
3/7

1. 자바 리플렉션 (Reflection)이란?

리플렉션 (Reflection)자바에서 클래스나 멤버에 대한 정보를 런타임에 조사하고, 조작할 수 있는 기능이다. 예를 들어, 클래스의 이름, 메서드, 필드, 생성자, 어노테이션 등에 대한 정보를 프로그램 실행 중에 알아내고, 이를 통해 객체를 생성하거나 메서드를 호출할 수 있다. 이 기능 덕분에, 개발자는 코드의 유연성과 확장성을 높일 수 있다.

이러한 기능을 가진 리플렉션은 프레임워크 (예: 스프링 등)에서 많이 사용되는데 예를 들어, 의존성 주입 (Dependency Injection)이 그 중 하나다. 스프링은 리플렉션을 통해서 클래스의 메타데이터를 분석하고, @Autowired 어노테이션이 붙은 필드를 찾아서 자동으로 의존성을 주입해 준다.

이 과정에서 스프링 컨테이너는 리플렉션을 사용해서 해당 필드의 타입에 맞는 빈 (bean)을 찾고, 그 빈을 해당 필드에 할당한다. 이를 통해 개발자는 객체의 생성과 의존성 관리를 수동으로 하지 않아도 된다. 이런 방식으로 스프링은 개발자가 더 쉽고 유연하게 애플리케이션을 구성하고 확장할 수 있게 도와준다.


2. 자바 리플렉션의 특징

자바 리플렉션의 특징은 다음과 같다.

특징설명
유연성실행 시에 동적으로 클래스를 다룰 수 있기 때문에, 정적 코딩으로는 불가능한 작업을 수행
프로그래밍 복잡도동적으로 코드를 작성하기 때문에 일반 코드보다 복잡함
성능 오버헤드리플렉션을 사용할 경우 일반적인 메서드 호출보다 느릴 수 있음.
따라서 성능에 민감한 부분에서는 주의 필요
보안 문제private 멤버에 접근할 수 있으므로, 잘못 사용하면 보안 취약점이 발생 가능
유지보수코드의 의존성이 명시적이지 않아, 리팩토링 시 주의가 필요

3. 예제 코드

아래 예제는 Person 클래스를 대상으로 리플렉션을 사용해 private 필드와 메서드에 접근하는 방법을 보여준다.

Person.java 파일

✍️ 작성

package com.example;

public class Person {
    private String name = "홍길동";

    public Person() {}

    private void printName() {
        System.out.println("이름: " + name);
    }
}

ReflectionExample.java 파일

✍️ 작성

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

public class ReflectionExample {
    public static void main(String[] args) {
        try {
            // 1. 문자열로부터 Person 클래스의 Class 객체를 얻어온다.
            Class<?> personClass = Class.forName("com.example.Person");

            // 2. 기본 생성자를 사용하여 인스턴스 생성 (동적 객체 생성)
            Object personInstance = personClass.getDeclaredConstructor().newInstance();

            // 3. private 필드 'name'에 접근하기 위해 Field 객체를 얻어온다.
            Field nameField = personClass.getDeclaredField("name");
            nameField.setAccessible(true);  // private 필드 접근 허용
            String nameValue = (String) nameField.get(personInstance);
            System.out.println("private 필드 값: " + nameValue);

            // 4. private 메서드 'printName'에 접근하여 호출한다.
            Method printMethod = personClass.getDeclaredMethod("printName");
            printMethod.setAccessible(true); // private 메서드 접근 허용
            printMethod.invoke(personInstance);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

코드 설명

1. Class.forName("com.example.Person")

  • 해당 메서드는 런타임에 문자열 "com.example.Person"을 기반으로 해당 클래스(Person)를 로딩해서 Class 객체를 반환
  • 덕분에 컴파일 타임에 어떤 클래스가 사용될지 몰라도, 실행 시 동적으로 해당 클래스를 결정 가능.

2. 동적 객체 생성

  • getDeclaredConstructor().newInstance()를 통해 Person 클래스의 기본 생성자를 호출하여 인스턴스를 생성.
  • 이때 리턴 타입은 Object이므로, 특별한 처리가 없다면 형변환 없이 Object로 사용하거나 필요에 따라 캐스팅 가능.

3. private 멤버 접근

  • getDeclaredField("name")getDeclaredMethod("printName")를 사용해 Person 클래스private 필드와 메서드에 접근.
  • setAccessible(true)로 접근 제한을 해제한 후 필드 값을 읽거나 메서드를 호출.

본 예제에서는 그냥 Class.forName("com.example.Person")으로 어떤 클래스를 받을지 명시해놓았지만 실제 애플리케이션에서는 이 부분이 외부 설정 파일이나 사용자 입력 등으로부터 받아온 문자열에 의해 결정될 수 있다.

즉, 코드 작성 시점에 어떤 클래스가 로딩될지 미리 정해져 있는 게 아니라, 실행 중에 입력된 값에 따라 동적으로 클래스를 로딩할 수 있다는 의미이다.

4. 해당 게시글 작성에 참고한 글 목록

[Java] 리플렉션 (Reflection)이란 무엇일까? (개념/ 예시)
[Java] 자바 리플렉션(reflection)이란?

profile
개발돌이

0개의 댓글