자바(Java) – Reflection 리플렉션 (RTTI:Run-Time Type Information)
1. RTTI 란?
- 실행 시간에 객체들의 정보(타입)를 얻는 표준화된 방법을 제공
- 런타임에 타입의 정보를 가지고 오류를 검사하는 목적으로 사용
Run Time Type Information의 약자로 "실행시간에 타입정보를 식별" 즉, 실시간으로 현재 사용되고 있는 클래스의 타입이 에 대한 정보를 알아보기 위해서 사용한다. 한글로 풀이하자면 "실시간 형식 정보" 라고 할 수 있겠죠.
정확한 의미는, 실행중에 기반 클래스 타입 객체의 타입에 대한 정보를 얻을 수 있는 기능입니다.
RTTI는 다형성 객체의 동적 타입을 알아내기 위해 만들어진 기능입니다. 즉, base* 타입의 포인터가 포인팅하고 있는 객체가 실제로 derived1 타입의 객체인지, derived2 타입의 객체인지를 알고자 할 때 쓰이는 것이죠.
2. RTTI 는 왜 필요한가?
RTTI는 위에서 언급했듯 실행중에 기반 클래스 타입 포인터의 실체를 밝혀내는데 목적으로 하고 있습니다.
정확하게 다형성을 가진 객체에 대해 정확한 타입을 알아내기 위해서 나왔다고 볼 수 있습니다.
RTTI(Run-Time Type Information)을 이용하면 실행중에 타입 정보를 알아내고 사용할 수 있다. 이는 매우 까다롭고 복잡한 문제점들을 쉽고 빠르게 해결 할 수 있고, 굉장히 강력한 프로그램을 작성 할 수 있게 도와준다. 하지만 이는 객체 지향적인 프로그래밍 방법을 위배하고, 코드의 가독성을 떨어트린다는 의견도 있다. 그렇지만 이런 강력한 기능의 유혹을 벗어나긴 힘들다. 그리고 실제 여러 Framework에서 RTTI를 잘 활용 하고 있다. (특히나 Spring Framework)
자바에서는 모든 .class 파일 하나당 java.lang.Class 객체 하나씩 생성된다. Class는 모든 .class들의 정보를 가지고 있으며 .class파일에 같이 저장된다. 모든 .class들은 이 클래스를 최초로 사용하는 시점에서 동적으로 ClassLoader을 통해 JVM에 로드된다.
간단한 예를 들면 Base 클래스가 있고 그것을 상속받은 Child1, Child2 클래스가 존재한다고 가정했을때,
Base* m_Base = new Child1(); 이렇게 할당하였을 경우 기존의 방법으로는 실행중에 m_Base 가 가리키고 있는 객체가
Child1 이라는 것을 알 수가 없습니다. 하지만 RTTI 를 사용하면 Child1 타입이라는 것을 정확하게 알 수 있게 됩니다.
이것은 하나의 단편적인 예이며 사실 가상함수를 사용하는 다형성을 통해서 굳이 런타임때 타입을 알필요가 없을지도 모릅니다. 하지만 가상함수로도 해결할 수 없는 문제점을 RTTI 를 통해서 해결 가능한 부분들이 존재합니다.
이에 관해서는 http://blog.naver.com/moodern?Redirect=Log&logNo=80005025903 를 참고하세요 ^^
3. 사용 방법
RTTI는 언어의 기능, 혹은 컴파일러의 기능을 칭하는 명칭이기도 합니다. 물론, 객체마다 유지되는 동적 타입을 가리키는 C++의 용어이기도 합니다.
RTTI 기능을 켜고 컴파일하면 type_info 클래스의 객체가 각 클래스마다 하나씩 만들어지고 가상함수 테이블에서 참조하게 됩니다. 사용방법은 4의 동작방식을 확인하세요.
[RTTI는 직접적으로 쓰는 경우는 많이 없다. 이전 회사까지 실무에서는 RTTI를 직접적으로 쓴적은 없었다. 단지 RTTI로 안전성을 확보한 표준 캐스트 연산자는 사용을 한다..]
4. RTTI의 동작 방식
1. dynamic_cast
base class를 지시하는 포인터로부터 파생클래스를 지시하는 포인터를 생성, 불가하면 NULL 리턴
안전성을 확보하는 과정에서 RTTI로 타입 검사를 거치게 된다.
(상속 관계에 있지만, 변환이 안되는 경우에 NULL을 리턴)
2. typeid
- 객체의 정확한 데이터형을 식별하는 값을 리턴
- typeid 연산자를 사용하여 두 객체의 데이터형이 같은지 결정할 수 있다.
- sizeof와 비슷하게, typeid 연산자는 두 종류의 전달인자를 받아들인다.(클래스이름, 객체로 평가되는 식-
- typeid 연산자는 type_info 객체에 대한 참조를 리턴한다.
3. type_info
- 반환된 typeid 연산자 형식의 정보를 저장하는데 사용
- RTTI는 가상 함수들을 가지고 있는 클래스 계층에 대해서만 사용할 수 있다. 이유는 그들이
파생 객체들의 주소를 기초클래스 포인터들에 대입해야 하는 유일한 클래스 계층이기 때문이다.
- ypeinfo 헤더 파일에 정의되어 있는 클래스이다.
- type_info 클래스는 데이터형을 비교하는데 사용할 수 있도록 == 과 != 연산자를 오버로딩한다.
- typeid(classA) == typeid(*classB), classB가 classA 객체를 지시하는 포인터이면 true,
아니면 false, NULL이면 bad_typeid 예외 발생
· dynamic_cast
o 포인터가 지시하는 객체형이 무엇인지 알려주진 않지만, 그 객체의 주소를 특정형의 포인터에 안전하게 대입할수 있는지 알려준다.
o 데이터형을 알려고 하는 일반적인 이유는, 어떤 특별한 메소드를 호출하는 것이 안전한지 알기 위한 것이다.
o 사용하는 컴파일러가 RTTI를 지원한다 하더라도, 그 기능이 디플트로 꺼져 있을 수 있다. 기능이 꺼져 있으면proj 속성 페이지를 열고, C/C++탭 -> 런타임 형식 -> '예' 로 변경
· typeid
o typeid 연산자를 사용하여 두 객체의 데이터형이 같은지 결정할 수 있다.
o sizeof와 비슷하게, typeid 연산자는 두 종류의 전달인자를 받아들인다.(클래스이름, 객체로 평가되는 식)
o typeid 연산자는 type_info 객체에 대한 참조를 리턴한다.
· type_info
o typeinfo 헤더 파일에 정의되어 있는 클래스이다.
o type_info 클래스는 데이터형을 비교하는데 사용할 수 있도록 == 과 != 연산자를 오버로딩한다.
o typeid(classA) == typeid(*classB), classB가 classA 객체를 지시하는 포인터이면 true, 아니면 false, NULL이면bad_typeid 예외 발생
5. RTTI의 제약사항
1) 상속 관계안에서만 사용할 수 있다.
2) 하나 이상의 가상 함수를 가져야 한다.
3) 컴파일러의 RTTI 설정이 켜저 있어야 한다.
'개발 > JAVA' 카테고리의 다른 글
[JAVA] 맥 이클립스 실행 단축키 (0) | 2016.02.10 |
---|