Reflaction

Single Ko·2023년 4월 4일
0

java

목록 보기
10/28

Reflaction 이란?

  • Java에서 제공하는 기능 중 하나로, 프로그램 실행 중에 클래스의 정보를 가져와서 클래스의 생성자, 필드, 메서드 등을 동적으로 조작하는 기법.
  • 이를 통해 개발자는 컴파일 시간에 알 수 없는 클래스를 런타임 시간에 동적으로 로딩하여 사용 할 수 있다.

Reflection의 활용

  • JVM은 Reflection API를 사용하여 클래스의 정보를 분석하고, 클래스의 인스턴스를 생성하고, 메서드와 필드를 호출한다.
  • 프레임워크나 라이브러리에서는 Reflection을 사용하여 런타임에 클래스의 정보를 분석하고, 객체를 동적으로 생성하거나 메서드를 호출하는 등의 작업을 수행.
  • 디버깅 도구나 테스트 도구에서도 Reflection을 활용하여 클래스의 정보를 분석하고, 객체의 상태를 확인하는 등의 작업을 수행.

기능 사용 예제

"필드 접근"

리플렉션을 사용하여 어떤 필드들이 존재하는지 검사할 수 있습니다.

public class Person {
    public String name;
    protected int age;
  	private int phoneNum;
    String personNum;
}

"getDeclaredFields()"

getgetFields() 메서드는 pulblic으로 선언된 필드만 조회가 가능하기 때문에 getDeclaredFields() 메서드를 사용해보겠습니다.

public static void main(String[] args) {
    Class<Person> clazz = Person.class; 
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        System.out.println(field.getName());
    }
}

결과

name
age
phoneNum
personNum

"인스턴스 생성하기"

생성자를 통해 인스턴스를 생성. 필드를 조회할 때는 필드를 조회하는 메서드를 사용했고, 이번엔 생성자를 가져오는 메서드를 사용한다.

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

    public Person() {}

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

    public Person(int age) {
        this.age = age;
    }

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

"getConstructor()"

타입을 명시하여 원하는 생성자를 조회할 수 있습니다. 해당되는 생성자가 없을 수도 있기 때문에 try-catch 문을 사용해야 합니다.

Class<Person> clazz = Person.class;
  
try {
    Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}

"newInstance()"

생성자를 가져왔다면 newInstance() 메서드를 사용하여 인스터를 생성할 수 있습니다.

Class<Person> clazz = Person.class;
  
try {
    Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
    Person person = constructor.newInstance("호호맨", 20);
} catch (Exception e) {
    e.printStackTrace();
}  

"메서드 접근하기"

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

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

    @Override
    public String toString() {
        return "이름 : " + this.name + ", 나이 : " + age;
    }
}

"getMethod()"

toString은 pulbic 메소드이므로 getDeclaredMethod()메소드를 사용하지 않아도 된다.

Class<Person> clazz = Person.class;
  
try {
    Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
    Person newPerson = constructor.newInstance("호호맨", 20);
    Method toString = newPerson.getClass().getMethod("toString");
} catch (Exception e) {
    e.printStackTrace();
}

"invoke()"

invoke() 를 사용하여 조회해온 toString() 메서드를 실행시켜보겠습니다.

public static void main(String[] args) {
    Class<Person> clazz = Person.class;
  
    try {
        Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
        Person newPerson = constructor.newInstance("호호맨", 20);
        Method toString = newPerson.getClass().getDeclaredMethod("toString");
        String result = (String)toString.invoke(newPerson);
        System.out.println(result);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

결과

이름 : 호호맨, 나이 : 20
  • invoke(Object obj, Object... args) 메서드는 인자로 해당 클래스 타입과 해당 메소드의 인자들을 인자로 받습니다.
  • invoke() 메소드는 라이브러리 내부를 디버깅할 때 정말 많이 보게 되는 메소드입니다.
  • invoke() 메소드가 보인다면 대부분 리플렉션을 사용한 기능일 것이다.

그냥 생성하면 되지 왜 어렵게 생성하나요?

  • Java를 사용한다면 Person person = new person(); 으로 간단하게 생성하면 될 것을 어렵게 생성하였다. 프레임워크나 다른 라이브러리를 사용할 때는 구체적인 클래스를 알고 있기 때문에 리플렉션을 사용할 일이 드뭅니다.
  • 하지만 본인이 라이브러리를 만들어본다고 생각해 봅시다. 라이브러리를 사용하는 사용자가 어떤 클래스를 만들지 예상할 수 있을까요? 또는 무엇인가 동적으로 만들어주는 프로그램을 만들고자 하면 어려움을 겪게 될 것입니다.
  • 실제 Spring 프레임워크를 디버깅 하다보면 invoke()를 활용한 것을 많이 볼 수있다. Spring은 사용자가 어떤 클래스를 만드는지 모른다. 따라서 런타임시 동적으로 그 클래스의 정보를 가져올 수 있는 Reflection을 이용하는 것이다.
profile
공부 정리 블로그

0개의 댓글