프로그래밍

자바와 닷넷 리플렉션 비교

Jinwookoh 2025. 3. 2. 20:09

자바(Java)와 닷넷(.NET)의 Reflection(리플렉션) 기능을 비교해보겠습니다.
리플렉션은 클래스, 메서드, 필드 등의 메타데이터를 런타임에 동적으로 조회하고 조작하는 기능을 제공합니다.


1. 주요 차이점

비교 항목  Java (Reflection API) .NET (System.Reflection)
네임스페이스 java.lang.reflect System.Reflection
클래스 정보 조회 Class<?> 사용 Type 사용
메서드 호출 Method.invoke() MethodInfo.Invoke()
필드 값 변경 Field.set() FieldInfo.SetValue()
생성자 호출 Constructor.newInstance() ConstructorInfo.Invoke()
성능 일반 호출보다 느림 (JVM 최적화 가능) 일반 호출보다 느림 (JIT 최적화 가능)
보안 제한 setAccessible(true) 필요 BindingFlags 사용 가능

2. Java 리플렉션 예제

아래는 Java에서 리플렉션을 사용하여 클래스 정보를 조회하고 메서드를 호출하는 예제입니다.

🔹 Person 클래스 정의

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void sayHello() {
        System.out.println("Hello, my name is " + name);
    }
}

🔹 리플렉션 코드

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

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        // 1. 클래스 정보 가져오기
        Class<?> clazz = Class.forName("Person");

        // 2. 생성자 가져오기 및 객체 생성
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
        Object person = constructor.newInstance("John");

        // 3. 필드 수정 (private 접근 허용)
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(person, "Alice");

        // 4. 메서드 호출
        Method method = clazz.getDeclaredMethod("sayHello");
        method.invoke(person);  // 출력: "Hello, my name is Alice"
    }
}

3. .NET 리플렉션 예제 (C#)

.NET에서는 System.Reflection 네임스페이스를 사용합니다.

🔹 Person 클래스 정의

using System;

public class Person
{
    private string name;

    public Person(string name)
    {
        this.name = name;
    }

    public void SayHello()
    {
        Console.WriteLine($"Hello, my name is {name}");
    }
}

🔹 리플렉션 코드

using System;
using System.Reflection;

class ReflectionExample
{
    static void Main()
    {
        // 1. 타입 정보 가져오기
        Type type = typeof(Person);

        // 2. 생성자 가져오기 및 객체 생성
        ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(string) });
        object person = constructor.Invoke(new object[] { "John" });

        // 3. 필드 수정 (private 접근 허용)
        FieldInfo field = type.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance);
        field.SetValue(person, "Alice");

        // 4. 메서드 호출
        MethodInfo method = type.GetMethod("SayHello");
        method.Invoke(person, null);  // 출력: "Hello, my name is Alice"
    }
}

4. Java와 .NET 리플렉션 비교 요약

기능  Java  .NET
클래스 정보 조회 Class<?> clazz = Class.forName("Person"); Type type = typeof(Person);
생성자 호출 Constructor<?> constructor = clazz.getDeclaredConstructor(String.class); ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(string) });
필드 접근 Field field = clazz.getDeclaredField("name"); field.setAccessible(true); `FieldInfo field = type.GetField("name", BindingFlags.NonPublic
메서드 호출 Method method = clazz.getDeclaredMethod("sayHello"); method.invoke(person); MethodInfo method = type.GetMethod("SayHello"); method.Invoke(person, null);

5. 성능 고려사항

  • 리플렉션은 정적 호출보다 성능이 느리며, 남용하면 애플리케이션 속도에 영향을 줄 수 있습니다.
  • Java에서는 JVM의 최적화가 일부 가능하지만, setAccessible(true)를 사용하면 보안 문제가 발생할 수 있습니다.
  • .NET에서는 JIT 최적화가 일부 가능하지만, BindingFlags를 사용하면 필드/메서드 접근 속도가 추가로 저하될 수 있습니다.
  • 대안으로 동적 프록시(Java의 Proxy, .NET의 DynamicMethod) 또는 Expression Tree(C#)를 활용하면 성능 저하를 줄일 수 있습니다.

6. 결론

  • 기능적으로 Java와 .NET의 리플렉션은 매우 유사하지만, 네임스페이스 및 API 스타일에 차이가 있습니다.
  • Java에서는 Class, Method, Field 클래스를 사용하고, .NET에서는 Type, MethodInfo, FieldInfo 등을 사용합니다.
  • 성능상 일반적인 코드보다 느리므로, 리플렉션 사용을 최소화하는 것이 좋습니다.