오늘 수업을 들으며 멘토님께서 리플렉션을 가능한 피해서 프로젝트를 해봐라 라는 말씀을 해주셨다. 하지만 나는 리플렉션 자체를 몰라 검색을 해 알게 되었다..
Reflection
구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API
컴파일 시간이 아닌 실행 시간에 동적으로 특정 클래스의 정보를 추출할 수 있는 프로그래밍 기법
Reflection을 사용할 때
- 동적으로 클래스를 사용해야 할 때 필요하다.
- 다시말해 작성 시점에서 어떠한 클래스를 사용해야 할지 모르지만 런타임 시점에서 클래스를 가져와서 실행해야 하는 경우 필요하다.
- 대표적으로 Spring 프레임워크의 어노테이션 같은 기능들이 리플렉션을 이용하여 프로그램 실행 도중 동적으로 클래스의 정보를 가져와서 사용한다.
Reflection은 어떤 정보를 가져올 수 있을까?
- class
- Constructor
- Method
- Field
이와 같은 정보들을 가져올 수 있으며 해당 정보들을 가져와서 객체를 생성하거나 메서드를 호출하거나 변수의 값을 변경할 수 있다.
Reflection의 단점
- 컴파일 타임 타입 검사가 주는 이점을 하나도 누릴 수 없다. 예외 검사도 마찬가지이다.
- 코드가 지저분해지고 장황해진다.
- 성능이 떨어진다. 리플렉션을 통한 메서드 호출은 일반 메서드 호출보다 훨씬 느리다.
리플렉션은 아주 제한된 형태로만 사용해야 그 단점을 피하고 이점을 취할 수 있다.
리플렉션은 복잡한 특수 시스템을 개발할 때 필요한 기능이지만 단점도 많다.
컴파일 타임에는 알 수 없는 클래스를 사용하는 프로그램을 작성한다면 리플렉션을 사용해야 할 것이다.
단 되도록 객체 생성에만 사용하고, 생성한 객체를 이용할 때는 적절한 인터페이스나 컴파일 타임에 알 수 있는 상위 클래스로 형 변환해 사용해야 한다.
조금 더 검색을 해보니 이런 글도 있다. 자세한 내용은 이 블로그를 통해 봤으면 좋겠다.
리플렉션에 대한 오해와 진실
자바가 제공하는 Exception의 종류에는 Checked Exception, Run-time Exception 그리고 error가 있다. 이중 Checked Exception의 경우, 위와 같이 컴파일 단계에 catch 하거나 throw 해야만 컴파일 오류가 발생하지 않는다. 이는 Checked Exception은 예외 상황에서 프로그램적으로 복구할 수 있는 방법이 존재하는 경우를 위한 Exception이기 때문이다.
하지만 Reflection 사용에 따른 Exception으로부터 복구할 수 있는 상황이란 거의 없다. 예를 들어, 위의 Class Not Found Exception이 발생한다면, 이는 클라이언트가 잘못된 클래스 명을 넘겨주었거나 또는 해당 클래스가 없을 2가지 경우다. 이는 모두 프로그램 에러 상황으로 오히려 Run-time Exception에 가깝다.
결국, Reflection을 사용함으로써, 개발단계에서 조기에 발견될 수도 있었을 프로그램 에러들이 런타임시에 발생하게 되는 것이다. 이처럼 에러 상황이 늦게 발견하면 디버깅이 어려워지게 된다. 이와 같은 경우를 위해서, 런타임 시 디버깅을 위해 상세한 에러 메시징 기능을 포함하는 것이 좋다.
Reflection의 사용에 관한 사실들은 사실 사실이 아니다. 성능, 디버깅, 그리고 복잡성과 관련된 내용들은 잘못 사용된 예에서 파생한 오해들이다.
Reflection은 염려할 만큼의 성능저하를 가져오지 않는다. 대량의 if/else문이나 switch문 대신, 잘 설계된 Reflection은 객체지향 철학을 어기지 않으면서도 더 좋은 성능을 발휘할 수도 있다.
또한 디버깅이 어려운 것은 컴파일 단계에 처리할 수 있는 오류들이 실행 단계에 발생하기 때문이 아니다. 더 근본적인 이유는 Reflection을 사용할 경우에 발생할 런타임 에러 메시지를 최대한 상세하게 그리고 친절하게 표시하도록 Exception 전략을 설계하지 못했기 때문이다. 잘 설계된 Exception 처리 전략은 Reflection 뿐만 아니라 시스템의 전체적인 디버깅을 쉽게 만든다.
Reflection의 복잡성은 사실 개발자 개개인의 초점에 맞추었을 때의 얘기다. 하지만, Reflection의 사용은 개발자의 관점이 아닌 아키텍트 중심으로 설계되어야 한다. Reflection이 가장 유용한 곳이 바로 시스템의 아키텍처를 이루는 컴포넌트들이기 때문이다. 오히려 잘 설계된 Reflection이 제공하는 서비스는 개발을 더욱 단순화한다.
하지만 지나친 사용은 화를 부를 수 있다. Reflection을 적절히 사용했고 많은 이득이 따른다 하더라도, 더 간단한 해결책이 존재한다면, Reflection을 사용하지 말 것을 권한다. 단순한 해결책은 언제 어느 경우에나 최상의 선택이다.
Reflection의 사용은 양날의 검과 같다. 잘 사용한다면, 이름을 불러주었을 때, 여러분의 꽃이 되어 줄 것이다.
'Java' 카테고리의 다른 글
[Java] HashMap (0) | 2022.11.23 |
---|---|
[Java] ArrayList (0) | 2022.11.23 |
[Java] 싱글톤 패턴 (0) | 2022.11.02 |
[Java] 컬렉션 프레임워크 (0) | 2022.10.31 |
[Java] Optional 이란? (1) | 2022.10.23 |