본문 바로가기
강의 정리/더 자바, 코드를 조작하는 다양한 방법

리플렉션

by 이석준석이 2020. 12. 6.

0. 리플렉션

 

리플렉션은 Class API를 사용한다.

Class API 에 있는 함수들을 통해서 클래스의

  • Field 의 값, 혹은 이름
  • 상위 클래스
  • 인터페이스
  • 메소드 목록
  • 어노테이션 등 클래스에 대한 모든 정보에 접근할 수 있다.

왜?

  • JVM ClassLoader 가 로딩이 끝난 뒤에, Heap에 Class 타입에 대한(Class<MyClass>) Class 정보를 등록했기 때문이다.

  • Class 정보 가져오는 법
  • Book 이라는 클래스가 있는 경우, 아래와 같은 3가지 방법으로 Class 정보를 가져올 수 있다.
// .class 인스턴스를 이용해서 가져오는 방법
Class<Book> bookClass = Book.class

// 객체에 대한 인스턴스를 생성한 이후, .getClass() 로 가져오는 방법
Book book = new Book();
Class<? extends Book> bookClass2 = book.getClass();

// FQCN 을 이용해서 가져오는 방법
Class<?> bookClass3 = Class.forName("me.sjlee.Book");

 


 

1. 어노테이션과 리플렉션

 

1. Retention()

  • 바이트코드를 로딩했을 때 (Method 영역에 메모리상으로 올렸을 때) 메모리상에는 저장되지 않는다.
    • 바이트코드에는 남아있으나, 로딩 이후에 메모리에는 올라가지 않는다.
      • default = [@Retention(RetentionPolicy.CLASS]
    • 메모리상에 남게하고 싶다면 @Retention(RetentionPolicy.RUNTIME) 을 사용한다.

 

2. Target()

  • 어노테이션을 사용할 위치를 제한하고 싶다면 @Target() 을 사용한다.

 

3. 어노테이션 필드 타입

  • 어노테이션은 값을 제한된 타입만 가질 수 있다.
    • primitive
    • String
    • Enum
    • another Annotation
    • Class
    • 위의 5개의 배열 형식
  • 필드 사용
    • String name(); / @MyAnnotation(name="leesukjune")
  • 기본값 설정법
    • String name() default "leesukjune";
  • value 키워드
    • String value(); / @MyAnnotation("value 일때는 그냥 써도 된다.")

4. Interited()

  • 상위 클래스에서 상속받은 어노테이션을 같이 사용하기 위해 사용

Class 정보를 통해 조회

MyClass.class.getAnnotations();
MyClass.class.getDeclaredAnnotations();

2. 클래스 정보 수정

 

이러한 정보들을 이용해서 생성자 생성 / 필드값 변경 및 가져오기 / Method 실행하기 등을 할 수 있다.

  • Class.getConstructor
  • Class.getField
  • Class.getMethod

Book

public class Book {

    private int a;

    public Book() {
    }

    private int sum(int a, int b) {
        return a + b;
    }
}

 

예시) 객체 생성

// Class 타입의 클래스 정보 가져오기
Class<?> bookClass = Class.forName("demo.reflection.Book");

// NoArgsConstructor 인 경우 생성하기
Constructor<?> constructor = bookClass.getConstructor(null);
Book book = (Book) constructor.newInstance();

// AllArgsConstructor 인 경우 생성하기
Constructor<?> allArgsConstructor = bookClass.getConstructor(int.class);
Book book2 = (Book) allArgsConstructor.newInstance(123);

System.out.println("is instance? : " + (book instanceof Book));

 

예시) 필드 값 가져오기

Book book = new Book();

Field a = Book.class.getDeclaredField("a");
// private field 인 경우 아래처럼 접근 가능할 수 있도록 해줘야 함
a.setAccessible(true);
// 값을 가져오기 위해서 인스턴스가 필요함
System.out.println(a.get(book));

 

예시) 메서드 수행하기

Method method = Book.class.getDeclaredMethod("method", int.class, int.class);

method.setAccessible(true);

int invoked = (int) method.invoke(new Book(), 1, 2);

System.out.println(invoked);