맞는데 왜 틀릴까..?

Java/Effective Java

[Effective Java] Item 65. 리플렉션보다는 인터페이스를 사용하라

안도일 2023. 7. 30. 15:51

 

리플렉션(Reflection)

프로그램 실행 중에 클래스의 정보를 동적으로 가져오고, 해당 클래스의 인스턴스를 생성하거나 메서드를 호출하는 기능을 말한다. 즉, 리플렉션을 통해 실행 중인 자바 프로그램이 자신의 구조를 분석하고 수정할 수 있는 능력을 갖게 된다.

 

 

1. 리플렉션 기능을 이용하면 프로그램에서 임의의 클래스에 접근할 수 있다.

  • Class 객체가 주어지면 그 클래스의 생성자, 메서드, 필드에 해당하는 Constructor, Method, Field 인스턴스를 가져올 수 있고, 이어서 이 인스턴스들로는 그 클래스의 멤버 이름, 필드 타입, 메서드 시그니처들을 가져올 수 있다.
  •  Constructor, Method, Field 인스턴스를 이용해 각각에 연결된 실제 클래스의 인스턴스를 생성하거나, 메서드를 호출하거나, 필드에 접근할 수 있다.

 

2. 리플렉션을 이용하면 컴파일 당시에 존재하지 않던 클래스도 이용할 수 있다.

 

 

리플렉션의 단점

 

1. 컴파일타임 검사가 주는 이점을 하나도 누릴 수 없다.

  • 예외 검사도 마찬가지다. 프로그램이 리플렉션 기능을 써서 존재하지 않는 혹은 접근할 수 없는 메서드를 호출하려 시도하면 런타임 오류가 발생한다.

 

2. 리플렉션을 이용하면 코드가 지저분하고 장황해진다.

 

3. 성능이 떨어진다.

  • 리플렉션을 통한 메서드 호출은 일반 메서드 호출보다 훨씬 느리다.

 

단점이 명백하기 때문에 코드 분석 도구나 의존관계 주입 프레임워크 처럼 리플렉션을 써야 하는 복잡한 애플리케이션도 리플렉션 사용을 줄이고 있다.

만약 내가 만든 애플리케이션에 리플렉션이 필요한지 확신할 수 없다면 아마도 필요 없을 가능성이 크다.

 

 

 

리플렉션 활용

 

리플렉션은 아주 제한된 형태로만 사용해야 그 단점을 피하고 이점만 취할 수 있다.

컴파일타임에 이용할 수 없는 클래스를 사용해야만 하는 프로그램은 비록 컴파일타임이라도 적절한 인터페이스나 상위 클래스를 이용할 수는 있으므로, 리플렉션은 인스턴스 생성에만 쓰고, 이렇게 만든 인스턴스는 인터페이스나 상위 클래스로 참조해서 사용하자.

 

 

리플렉션으로 생성하고 인터페이스로 참조해서 활용

 

 

  • Set<String> 인터페이스의 인스턴스를 생성
  • 정확한 클래스는 명령줄의 첫 번째 인수로 확정
  • 생성한 set에 두 번째 이후의 인수들을 추가한 다음 화면에 출력
  • 첫 번째 인수와 상관없이 이후의 인수들에서 중복은 제거한 후 출력
  • 인수들이 출력되는 순서는 첫 번째 인수로 지정한 클래스가 HashSet 인지, TreeSet인지에 따라 결정됨

 

 

두 가지 단점

 

1. 런타임에 총 여섯 가지나 되는 예외를 던질 수 있다.

  • 6가지 모두가 인스턴스를 리플렉션 없이 생성했다면 컴파일타임에 잡아낼 수 있었을 예외다.

2. 클래스 이름만으로 인스턴스를 생성해 내기 위해 무려 25줄이나 되는 코드를 작성했다.

  • 리플렉션이 아니라면 생성자 호출 한 줄로 끝났을 일이다.

 

두 단점 모두 객체를 생성하는 부분에만 국한된다.

객체가 일단 만들어지면 그 후의 코드는 여타의 Set 인스턴스를 사용할 때와 같다.

 

 

리플렉션은 런타임에 존재하지 않을 수도 있는 다른 클래스, 메서드, 필드와의 의존성을 관리할 때 적합하다. 

버전이 여러 개 존재하는 외부 패키지를 다룰 때 유용하다.

 

 

 

결론

 

  • 리플렉션은 복잡한 특수 시스템을 개발할 때 필요한 강력한 기능이지만 단점도 많다.
  • 컴파일타임에는 알 수 없는 클래스를 사용하는 프로그램을 작성한다면 리플렉션을 사용해야 할 것이다.
  • 단, 되도록 객체 생성에만 사용하고, 생성한 객체를 이용할 때는 적절한 인터페이스나 컴파일타임에 알 수 있는 상위 클래스로 형변환해 사용해야 한다.