리플렉션

hyyyynjn·2021년 4월 16일
1

자바 스터디

목록 보기
8/15
post-thumbnail
  • 리플렉션에 대해 설명하기

Reflection이란

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

Reflection을 사용하는 이유

컴파일 언어(정적인 언어)인 자바에 없는 동적으로 객체를 생성하는 기술을 Reflection으로 대신한다.

✋ 정적인 언어 : Compile 시점에 타입을 결정하는 언어 (Java, C/C++)
✋ 동적인 언어 : Runtime 시점에 타입을 결정하는 언어 (Javascript, Python)

Reflection의 특징

✍ 확장성 특징

어플리케이션이 정규화된 이름을 사용하게 하여 확장성 객체의 인스턴스를 생성하여 외부 사용자 정의 클래스를 사용할 수 있게 한다.

✍ 클래스 브라우저 및 시각적 개발 환경을 제공

클래스의 Method, Property, Constructor를 열거할 수 있고, 개발자가 올바른 코드를 작성하는데 도움이 되도록 Reflection에서 사용할 수 있는 형식 정보를 제공한다.

✍ 디버거 및 테스트 도구

개인 Property, Method, Constructor를 검사

Reflection의 단점

✍ 오버헤드

Reflection에는 동적으로 해석되는 유형이 있기에 특정 JVM 최적화를 수행할 수 없다. 그 이유로 비 Reflection 작업보다 성능면에서 떨어진다.

✍ 보안 제한 사항

✍ 캡슐화 저해

비 Reflection 코드에서 작동하지 않는 코드 (private한 Property및 Method에 액세스)를 수행하게되어 예기치 않은 부작용을 발생시킬 수 있고, 추상화를 꺠뜨릴 수 있다.

Reflection을 사용하는 기술

  • JVM에서 실행되는 어플리케이션의 런타임 동작을 검사하거나 수정할 수 있는 기능이 필요한 프로그램에서 사용된다. 즉, 동적으로 클래스를 사용해야 할때 필요하다.
  • Reflection은 애플리케이션 개발에서보다는 프레임워크, 라이브러리에서 많이 사용된다.
  • Spring 프레임워크
    • 스프링 부트의 Annotation
    • 스프링의 DI(dpendency injection)
  • 하이버네이트 ORM
  • Jackson 라이브러리
  • Intellij IDE의 자동완성
    • 시각적 개발환경을 제공하는 기술

예제

자바 예제

Class.getClass()를 통해 클래스의 정보 로드하기

상속된 클래스를 포함하여 모든 공용 클래스, 인터페이스 및 열거형을 반환

//임의의 클래스를 가져오는 방법
Class c = "foo".getClass();
System.out.println(c);      //class java.lang.String

//Array는 객체이므로 Array 인스턴스에서 클래스 정보를 로드할 수 있습니다.
byte[] b = new byte[1024];
Class c1 = b.getClass();
System.out.println(c1);     //class [B

Set<String> s = new HashSet<>();
Class c2 = s.getClass();
System.out.println(c2);     //class java.util.HashSet

Primitive Type.class를 통해 정보 로드하기

  • Primitive Type(원시타입)
  • 다차원 배열
  • java.io Type
boolean bl;
Class c3 = bl.getClass();   //컴파일 에러 발생
Class c4 = boolean.class;

Class c5 = java.io.PrintStream.class;
System.out.println(c5);     //class java.io.PrintStream

Class c6 = int[][].class;
System.out.println(c6);     //class [[I

TYPE 필드로 Reference Type(참조타입)의 원시형 클래스 반환하기

Class c8 = Double.TYPE;     //double
Class c9 = Void.TYPE;       //void

Class.forName()으로 클래스 로드하기

//아래와 같이 패키지 명으로 클래스를 로드할 수 있습니다.
Class c7 = Class.forName("ko.maeng.reflection.ReflectionApplication");
Class doubleArray = Class.forName("[D");    //class [D
Class stringArray = Class.forName("[[Ljava.lang.String;");  //class [Ljava.lang.String;

.isInstance() 메소드로 인스턴스 확인하기

    try{
        Class c = Class.forName("ko.maeng.reflection.A");
        boolean b = c.isInstance(new Integer(22));
        System.out.println(b);  //false
        
        boolean b1 = c.isInstance(new A());
        System.out.println(b1); //true
    } catch (ClassNotFoundException e){
        e.printStackTrace();
    }

스프링 부트 예제

@Controller
@RequestMapping("/articles")
public class ArticleController {    

    @Autowired    
    private ArticleService articleService;       
       ....

    @PostMapping
    public String write(UserSession userSession, ArticleDto.Request articleDto){
       ...
    }

    @GetMapping("/{id}")
    public String show(@PathVariable int id, Model model) {
       ...
    }
}

@Controller 를 넣어주면 인스턴스를 생성 하지 않아도 스프링이 알아서 생성해서 빈으로 관리해준다.

  • 의문
    • 스프링은 ArticleController의 존재를 어떻게 알고 만들어줄까?
    • ArticleService 라는 필드는 어떻게 주입해줄까?
    • 모든 메소드의 파라미터 개수, 타입이 다른데 어떻게 알고 해당하는 값을 바인딩 해줄까?

👉 스프링은 ArticleController의 정보를 알아내기 위해서 Reflection을 사용한다


0개의 댓글