스프링이 실행시점에 빈을 주입하게 해준다거나... JPA Entity에서 기본생성자를 통해 사용된다...
실체(Class)에 거울(JVM 메모리영역)에 비춘 것
실행순서 : 자바코드가 컴파일러에 의해 바이트코드로 변환된다. 클래스로더는 이 바이트 코드를 읽어 JVM메모리 영역에 저장된다. 리플렉션은 이 메모리 영역 저장된 클래스 정보를 꺼내와서 필드 메소드를 가져와 사용한다.
클래스에 붙은 것들을 조회 가능하며
Class는 실행중인 자바어플리케이션의 클래스와 인터페이스의 정보를 가진 클래스! 라고 이해하면 된다. 참고로 JVM에 의해 자동으로 생성된다.
Class<?> clazz = Person.class;
Person 춘식 = new Person("춘식");
Class<?> clazz = 춘식.class;
Class<?> clazz = Class.forName("org.example.Person");
getMethods와 getDeclaredMethods를 구분해야한다는 것이다!
Class<?> clazz = Class.forName("org.example.Person");
Constructor<?> constructor = clazz.getDeclaredConstructor();
//갖고온 생성자를!
Object person1 = constructor1.newInstance();
-> 생성자의 접근제어자가 private라면...에러가 발생하지만 리플렉션을
활용하면
constructor1.setAccessible(true); <<-- 접근제어 가능!
Object person = constructor.newInstance("나사람","29");
Field[] fields = claz.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
method.setAccesible(true);
System.out.println(method);
}
해당 메소드를 출력하면 접근제어자, 리턴타입, 메소드명, 파라미터 타입도 들고 올수 있다.
추가적으로 메소드 호출도 가능하다
Method method = clazz. getDeclaredMethod("메소드명", 파라미터타입) //이렇게 구성하고
Method method = clazz. getDeclaredMethod("walk", int.class);
method.setAccessible(true);
method.invoke(person,3);
리플렉션은 프레임 워크나 라이브러리에 사용된다. 왜냐 실제 코딩할때는 개발자는 객체 타입을 모르는 경우가 없기 때문. BUT 컴파일 시점에는 객체의 타입을 모른다.
기본 생성자로 객체를 생성하고, 필드를 통해 값을 넣어주는 것이 간단한 방법!!
---> 결국 이것도 리플렉션을 이용..
1. 리플렉션을 통해 클래스,메서드, 파라미터 정보를 가져온다.
2. 리플렉션의 getAnnotations, getDeclaredAnnotation등의 메서드를 통해 원하는 어노테이션이 붙어있는지 확인한다.
3. 어노테이션이 붙어 있다면 원하는 로직을 수행한다.
일반 메소드 호출보다 성능이 훨씬 떨어짐...(런타임 시점에서 클래스가 생성되서 JVM을 최적화 할 수없다..)
컴파일 시점에서 타입 체크기능을 사용할 수 없음..
EX) 존재하지 않는 클래스를 접근해도 컴파일 시점에선 알수 없음..
코드 가독성 저하..
추상화 및 불변성을 파괴한다..