더자바 리플렉션 (1)
728x90

인프런에 있는 백기선님의 더 자바, 코드를 조작하는 다양한 방법 을 보고 정리하는 글입니다.

리플렉션

리플렉션으로 알아볼 수 있는 것들

일단 maven 프로젝트를 생성한다.


App 클래스가 있는 패키지 경로에 Book을 생성.


Book에 접근제한자를 다양하게 선언해본다.


Book.java

public class Book {

    private static String B = "BOOK";

    private static final String C = "BOOK";

    private String a = "a";


    public String d = "d";

    protected  String e = "e";


    public Book() {}


    public Book(String a, String d, String e) {
        this.a = a;
        this.d = d;
        this.e = e;
    }

    private void f() {
        System.out.println("F");
    }

    public void g() {
        System.out.println("g");
    }

    public int h() {
        return 100;
    }
}


이제 Book에 어떤 필드, 어떤 메소드 등이 쓰였는지 확인 하기 위해 Class라는 api를 사용한다.
어떠한 클래스의 정보를 가져오는 방법

  1. 클래스의 인스턴스를 가져오는 방법
// Book.class
 Class<Book> bookClass = Book.class;

// FQCN (Fully Qualified Class Name) 만 알 때
 Class<?> aClass1 = Class.forName("me.whiteship.Book");
  1. 필드를 가져오고 싶을 때
 Field[] fields = bookClass.getFields();

 //public 한 것만 가져오고 싶은 경우
 Array.stream(bookClass.getFields()).forEach(System.out::println);

 //접근 제한자 상관 없이 가져오는 경우
 Book book = new Book(); // Book 클래스 선언
 Array.stream(bookClass.getDeclaredFields()).forEach(f-> {

     try {
       f.setAccessible(true);// 무조건 접근 가능하게 하려면
       System.out.printf("%s %s\n",f,f.get(book));;  // 이것만 사용하는 경우에는 Error 접근 불가능한 것에 접근하기 때문
      } catch (IllegalAccessException e) {
              e.printStackTrace();
      }
 }) 
  1. 메소드를 가져올 때
  //Object를 상속하는 것도 가져온다.
  Arrays.stream(bookClass.getMethods()).forEach(System.out::println);

  // 메소드가 public인지 private 인지 static인지 알아볼때
        Arrays.stream(Book.class.getDeclaredFields()).forEach(f->{
            int modifiers = f.getModifiers();
            System.out.println(f);
            System.out.println(Modifier.isPrivate(modifiers));
            System.out.println(Modifier.isStatic(modifiers));
        });
  1. 생성자
  Arrays.stream(bookClass.getDeclaredConstructors()).forEach(System.out::println);
  1. 상위 클래스(super class)
  System.out.println(MyBook.class.getSuperclass()); // 상위 클래스는 1개이므로 배열로 가져올 수 없다.
  1. 인터페이스
   Arrays.stream(MyBook.class.getInterfaces()).forEach(System.out::println);
  1. 어노테이션
   Arrays.stream(Book.class.getAnnotations()).forEach(System.out::println); // 이렇게 하면 정보가 나오지 않는다.

7번의 어노테이션 정보가 나오지 않는 이유는 어노테이션은 기본적으로 주석으로 인식하기 때문이다.
하지만 바이트코드에는 남지만 바이트 코드를 로딩했을 때 주석이라고 인식하여 메모리 상에는 남지 않는다.
같이 읽어오고 싶으면 어노테이션에다가 @Retention(RetentionPolicy.RUNTIME) 을 해준다.

확인하는 방법

  1. @Annotation 생성

MyAnnotation

Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@Inherited //상속이 되는 어노테이션이다 라는 뜻
public @interface MyAnnotation {

    String name() default "yeonsang";
//  String value() default "yeonsang";

    int number() default 100;

}
  1. 어노테이션 사용

Book.java

@MyAnnotation
public class Book{...}
  1. javap 명령어 사용
    /target/classes 에서 해당 어노테이션이 사용된 클래스 경로를 복사 한 뒤에 터미널에서
    javap -c -v 복사한 경로

    출처 : 더 자바 , 코드를 조작하는 다양한 방법
728x90

'더 자바' 카테고리의 다른 글

더 자바 리플렉션(2)  (0) 2022.04.04
더 자바 바이트코드 조작  (0) 2022.03.31
더 자바 JVM  (0) 2022.03.31