리플렉션

이연중·2021년 1월 24일
0

JAVA

목록 보기
5/20

구체적인 클래스 타입을 알지 못해도 해당 클래스의 객체 생성, 메소드, 타입, 변수들에 접근할 수 있도록 도와주는 Java API

리플렉션 API: 클래스 정보 조회

리플렉션의 시작 - Class

Class에 접근하는 방법

  • 모든 클래스를 로딩 한 다음 Class의 인스턴스가 생긴다.(클래스 로더는 .class를 읽고 메서드 메모리에 저장한 다음, class 타입의 객체를 생성해 힙 영역에 저장한다) "타입.class"로 접근 가능
    예) Class bookClass = Book.class;

  • 모든 인스턴스는 getclass() 메소드를 가지고 있음. "인스턴스.getClass()"로 접근 가능
    예) Book book = new book;
    Class<? extends Book> aClass = book.getClass();

  • 클래스를 문자열로 읽어오는 방법

    • Class.forName("FQCN(Full Qulified Class Name 클래스 경로 풀네임)")
    • 클래스 패스에 해당 클래스가 없으면 ClassNotFoundException이 발생

    예) Class<?> aClass1 = Class.forName("me.alwayslee.Book");

Class를 통해 할 수 있는 것

  • 필드(목록) 가져오기(getModifiers()를 이용해 public, private, protective 확인 가능)

    ex) Arrays.stream(bookClass.getFields()).forEach(System.out::println);

    getFields() (public만) -> getDeclearedFields() 하면 모든 필드 가져옴.

    또한, setAccessible(true)로 하면 접근이 불가능한 필드도 접근이 가능하게 되어 필드의 값을 확인할 수 있음

  • 메소드(목록) 가져오기

    ex) Arrays.stream(bookClass.getMethods()).forEach(System.out::println);

  • 상위 클래스 가져오기

    ex) System.out.println(bookClass.getSuperclass())

  • 인터페이스(목록) 가져오기

    ex) Arrays.stream(MyBook.class.getInterfaces()).forEach(System.out::println);

  • 애노테이션 가져오기

  • 생성자 가져오기

    ex) Arrays.stream(bookClass.getDeclaredConstructors()).forEach(System.out::println);

리플렉션 API: 클래스 정보 수정 또는 실행

Class 인스턴스 만들기

  • Class.newInstance()는 deprecated 되었으니 생성자를 통해 만들어야 한다

  • Class<?> bookClass = Class.forName("me.alwayslee.Book");

    Constructor<?> constructor = bookClass.getConstructor(String.class);

    Book book = (Book) constructor.newInstance("myBook");

필드 값 접근하기/설정하기

  • 특정 인스턴스가 가지고 있는 값을 가져오는 것이기에 인스턴스 필요

  • Field a = Book.class.getDeclaredField("A");

    a.set(null,"AAA");

    null을 넣은 이유는 Static한 A가 Static한 필드이기 때문이다.(Static 필드는 Object가 없어도 되니 null을 넘긴다)

메소드 실행하기

  • Method b = Book.class.getDaclaredMethod("sum", int.class, int.class);

    b.invoke(book, 1, 2);

애노테이션과 리플렉션

  • 애노테이션은 '주석, 코멘트'와 같은 취급을 받기에 정보가 클래스까지는 남지만. 바이트 코드 로딩시 메모리 상에는 남지 않는다
  • 같이 읽어오고 싶다면, "@Retention(RetentionPolicy.RUNTIME)"를 붙인다
  • 위같이 하게 되면, 바이트 코드에 해당 애노테이션이 저장되고, getAnnotation()을 통해 애노테이션 정보 조회가 가능하게 된다

중요 애노테이션

  • @Retention: 해당 애노테이션을 런타임까지 유지(원래는 소스, 클래스까지만)
  • @Taget(ElementType.TYPE.ElementType.FIELD): 애노테이션의 위치를 제한할 수 있음(지정 범위 이외에 해당 애노테이션을 붙이게 될 경우 에러 발생)
  • @Inherit: 해당 애노테이션을 하위 클래스까지 유지. 하위 클래스에서 애노테이션 조회시 해당 애노테이션도 조회가 된다

리플렉션

  • getAnnotations(): 상속받은 애노테이션까지 조회
  • getDeclaredAnnotations(): 자기 자신에만 붙어있는 애노테이션 조회

리플렉션 정리

리플렉션 사용시 주의할 것

  • 지나친 사용은 성능 이슈를 야기할 수 있음(인스턴스가 만들어져 있음에도 리플렉션을 이용해 필드나 메서드에 접근하는 경우와 같이)
  • 컴파일 타임에 확인되지 않고 런타임 시에만 발생하는 문제를 만들 가능성이 있음
  • 접근 지시자 무시할 수 있음

스프링

  • 의존성 주입
  • MVC 뷰에서 넘어온 데이터를 객체에 바인딩 할 때

하이버네이트

  • @Entity 클래스에 Setter가 없다면 리플렉션 사용

JUnit

참고

참고

https://www.inflearn.com/course/the-java-code-manipulation

profile
Always's Archives

0개의 댓글