IT's 우

[java] 리플렉션(Reflection) 본문

CS/Java

[java] 리플렉션(Reflection)

디우 2023. 7. 14. 18:38
728x90

리플렉션

리플렉션(Reflection)이란?

👉 구체적인 클래스 타입을 알지 못해도 그 클래스의 메서드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API

 

런타임에 지금 실행되고 있는 클래스를 가져와서 실행해야하는 경우

동적으로 객체를 생성하고 메서드를 호출하는 방법

자바의 리플렉션은 클래스, 인터페이스, 메소드들을 찾을 수 있고, 객체를 생성하거나 변수를 변경하거나 메서드를 호출할 수 있다.

 

어떤 경우에 사용되나?

자바는 정적인 언어라 부족한 부분이 많은데 이 동적인 문제를 해결하기 위해서 리플렉션을 사용합니다.

 👉

  • 정적 언어: 컴파일 시점에 타입을 결정 ex) Java, C, C++ 등..
  • 동적 언어: 런타임 시점에 타입을 결정 ex) Javascript, Python, Ruby 등.. 

 

코드를 작성할 시점에는 어떤 타입의 클래스를 사용할지 모르지만, 런타임 시점에 지금 실행되고 있는 클래스를 가져와서 실행해야 하는 경우

리플렉션은 애플리케이션 개발에서보다는 프레임워크, 라이브러리에서 많이 사용됩니다.

프레임워크, 라이브러리는 사용하는 사람이 어떤 클래스를 만들지 모릅니다. 이럴 때 동적으로 해결해주기 위해서 리플렉션을 사용합니다.

대표적인 사용 예)

IntelliJ의 자동완성, 스프링의 DI(dependency injection), 스프링 어노테이션, Proxy, ModelMapper 등이 있습니다.

 

리플렉션을 사용하여 가져올 수 있는 정보

  • Class
  • Constructor
  • Method
  • Field

 

Java Reflection 사용 실습


Person이라는 클래스를 생성하고, 리플렉션을 사용해보자.

class Person {
    int age;

    Person() {
        this.age = 27;
    }

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

    int getAge() {
        return this.age;
    }
}

생성자 찾기

getDeclaredConstructor()를 이용해 클래스로부터 생성자를 가져올 수 있다.

getDeclaredConstructor()는 인자가 없는 생성자를 가져온다.

Class clazz = Class.forName("Person");
Constructor constructor = clazz.getDeclaredConstructor();

Method 찾기

Class clazz = Person.class;
Method[] methods = clazz.getDeclaredMethods();
System.out.println(methods[0].invoke(clazz.newInstance())) // 27이 출력됨

invoke() 메서드를 사용하면 Method 객체를 실행할 수 있다. 첫번째 인자는 호출하려는 객체, 두번째 인자는 전달할 파라미터 값을 준다.

Field 변경

필드 가져오기

Class clazz = Person.class;
Field[] field = clazz.getDeclaredFields();
System.out.println(field[0]);   
// 출력 : int reflection_test.Person.age

set() 메소드를 사용해서 객체의 변수를 변경할 수 있다.

Class clazz = Person.class;
Field[] field = clazz.getDeclaredFields();

Person person = new Person();
field[0].set(person, 17);
System.out.println(field[0].get(person));  // 17이 출력됨

장점

  • 런타임 시점에 사용할 instance를 선택하고 동작시킬 수 있는 유연한 기능을 제공한다.

단점

  • 컴파일 시점이 아니라 런타임 시점에서 오류를 잡기 때문에 컴파일 시점에 확인할 수 없다.
  • 접근 제어자로 캡슐화된 필드, 메서드에 접근 가능해지므로 기존 동작을 무시하고 깨뜨리는 행위가 가능해진다.
  • 위와 같은 단점 때문에 피할 수 있다면 사용을 자제하는 것이 좋다.
  • 사용처
    • 런타임 시점에 다른 클래스를 동적으로 로딩하여 접근할 때 사용
    • 클래스와 멤버 필드, 메서드 등에 관한 정보를 얻어야 할 때 사용

참고

https://velog.io/@yeon/Reflection이란

728x90
반응형