@RunWith(SpringRunner.class)
@SpringBootTest
public class BookServiceTest {
@Autowired
BookService bookService;
@Test
public void di() {
Assert.assertNotNull(bookService.bookRepository);
Assert.assertNotNull(bookService);
}
}
위의 코드를 실행하였을때 @Autowired 어노테이션을 썻다는것 만으로 BookService 객체를 생성하지 않더라도 NULL 값이 발생하지 않는다.
이게 어떻게 가능한일 일까?
리플렉션의 시작은 Class<T>
Class<T>에 접근하는 방법
-
모든 클래스를 로딩 한 다음 Class<T>의 인스턴스가 생긴다. “타입.class”로 접근할 수 있다.
-
모든 인스턴스는 getClass() 메소드를 가지고 있다. “인스턴스.getClass()”로 접근할 수 있다.
-
클래스를 문자열로 읽어오는 방법
-
Class.forName(“FQCN”)
-
클래스패스에 해당 클래스가 없다면 ClassNotFoundException이 발생한다.
Book 클래스 생성
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;
}
}
클래스로딩이 끝나면 클래스타입의 인스턴스를 만들어서 Heap 메모리 영역에 올린다. (클래스로딩은 런타임 시점)
클래스타입의 인스턴스를 가져오는 방법
방법1. 클래스타입에 직접 가져올때
Class<Book> bookClass = Book.class;
방법2. 인스턴트를 통할때
Book book = new Book();
Class<? extends Book> bookClass1 = book.getClass();
방법3. 문자열로 접근할 때
Class<?> aClass = Class.forName("me.choi.Book");
getFields : public 한 필드를 리턴
Arrays.stream(bookClass.getFields()).forEach(System.out::println);
d 밖에 안나오는 이유는
d만 public한 필드이기 때문이다.
getDeclaredFields : 접근제어자에 상관없이 모든 필드를 리턴
Arrays.stream(bookClass.getDeclaredFields()).forEach(System.out::println);
접근제어자 무시 (with setAccessible(true))
Arrays.stream(bookClass.getDeclaredFields()).forEach(f -> {
try {
System.out.printf("%s %s \n",f, f.get(book));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
위의 코드를 작성하면 에러 발생!
Arrays.stream(bookClass.getDeclaredFields()).forEach(f -> {
try {
f.setAccessible(true);
System.out.printf("%s %s \n",f, f.get(book));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
getMethods : 모든 메서드 불러오는 방법
Arrays.stream(bookClass.getMethods()).forEach(
System.out::println
);
getDeclaredConstructors : 모든 생성자 불러오는 방법
Arrays.stream(bookClass.getDeclaredConstructors()).forEach(System.out::println);
getInterfaces : 모든 인터페이스 불러오는 방법
Arrays.stream(MyBook.class.getInterfaces()).forEach(System.out::println);
기타기능
Arrays.stream(bookClass.getDeclaredFields()).forEach(f ->{
int modifier = f.getModifiers();
//접근제어자 확인
System.out.println(Modifier.isPublic(modifier));
System.out.println(Modifier.isPrivate(modifier));
System.out.println(Modifier.isStatic(modifier));
System.out.println(Modifier.isAbstract(modifier));
//리턴타입 확인
System.out.println(f.getReturnType());
});
'Java > Java' 카테고리의 다른 글
(JAVA) 리플렉션 API(3) - 클래스 정보 수정 또는 실행 (0) | 2019.12.23 |
---|---|
(JAVA) 리플렉션 API(2) - 애노테이션과 리플렉션 (0) | 2019.12.22 |
(JAVA) 바이트코드 조작(3) - javaagent (0) | 2019.12.22 |
(JAVA) 바이트코드 조작(2) (0) | 2019.12.22 |
(JAVA) 바이트코드 조작(1) (0) | 2019.12.22 |