리플렉션 기능을 이용하면 임의의 클래스에 접근 가능
클래스의 생성자, 메서드, 필드 등을 가져오고 조작 가능
- 컴파일 타임 타입 검사 이점을 받을 수 없다.
- ex) private 메소드를 호출할 때 setAccessble 하지 않으면 런타임 에러 발생!
- 코드가 지저분, 너저분, 장황해진다.
- 성능 이슈
- 고려해야 하는 요소들이 많아 오버헤드가 발생
- 컴파일 타임이 아닌 런타임에 동적으로 타입을 분석하고 정보를 가져오므로 JVM을 최적화할 수 없기 때문
결론적으로 Reflection은 애플리케이션 개발보다는 프레임워크나 라이브러리에서 많이 사용된다.
실제로 intellij의 자동완성, jackson 라이브러리, Hibernate 등등 많은 프레임워크나 라이브러리에서 Reflection을 사용하고 있다.
사용해야 할 때가 있는 이유는 분명하다. 동적으로 클래스를 생성하고 접근해야 할 때.
☝🏼 리플렉션은 인스턴스 생성에만 쓰기
☝🏼 이렇게 만든 인스턴스는 인터페이스나 상위 클래스로 참조해 사용하기
public interface Crew {
void setName(String name);
void sayMyCourseWithName();
}
public class Backend implements Crew {
private String name;
@Override
public void sayMyCourseWithName() {
System.out.println(name + "은 Backend 입니다.");
}
@Override
public void setName(String name) {
this.name = name;
}
}
public class Frontend implements Crew {
private String name;
@Override
public void sayMyCourseWithName() {
System.out.println(name + "은 Frontend 입니다.");
}
@Override
public void setName(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class<? extends Crew> crew = null;
try {
crew = (Class<? extends Crew>) Class.forName(args[0]);
} catch (ClassNotFoundException e) {
System.err.println("그런 클래스 없습니다.");
System.exit(1);
}
Constructor<? extends Crew> crewConstructor = null;
try {
crewConstructor = crew.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Crew eden = null;
try {
eden = crewConstructor.newInstance(); // new Backend() or new Frontend()
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
System.err.println("잘못된 요청입니다.");
}
eden.setName(args[1]);
eden.sayMyCourseWithName();
}
}
java item65.test.Main item65.test.Backend eden
eden은 Backend 입니다.
java item65.test.Main item65.test.Frontend jun
jun은 Frontend 입니다.
🐱 복잡한 특수 시스템(동적으로 클래스 생성 등)을 개발할 때 필요한 강력한 기능
🐱 강력한 기능인만큼 단점이 너무 큼
🐱 잘만 사용하면 우리도 프레임워크 컨트리뷰터!