JDK5에 등장한 Generic은 type parameter라는 개념을 도입하면서 자바 프로그래밍을 손쉽게 해줄 수 있는 멋진 언어기능으로 주목받아왔다. Generic을 이용해서 프로그래밍을 해보면 얼마나 편리하게 베이스클래스등을 만들 수 있는지 감탄하게 된다. 하지만 Generic을 좀 더 깊이 살펴보면 그다지 만만한 기술이 아닌 것을 알 수 있다. 자바 언어를 복잡하게 만든 대표적인 기술이라는게 Generic의 비판자들의 공통적인 주장이다. wildcard나 extend의 사용과 generic superclass, generic iterface등을 결합해서 쓸 때 주의 하지 않으면 매우 난해한 코드구조를 만들어 낼 수 있다.


OSAF개발을 할 때 Generic을 적용해서 제일 해피했던 것은 Spring의 HibernateDaoSupport를 Generic을 이용해서 generic DAO구조로 만든 것과 SpringMVC의 컨트롤러에 generic을 적용해 command object등의 불필요한 casting을 사용하지 않도록 만든 것이다.


하지만 문제는 Generic Enumeration을 만들때이다. singleton을 쓸까하다가 편하게 static을 쓰기로 했다. 문제는 static field, method에는 generic을 사용할 수 없다는 사실! 물론 generic method는 static에서 사용가능하지만 generic class의 type parameter를 static method에 적용하는 것은 불가능하다. 이유를 찾아보니 Java generic은 C++의 template과는 달리 컴파일시에 적용되는 것이 아니고 dynamic하게 인스턴스가 만들어질 때 적용된다는 것이다. 잘 이해가 안됐지만 그런가하고 포기하고 넘어갔다.


그러다가 최근에 Generic의 파라메터 정보를 읽어오면 편리하겠다 싶어서 reflection을 이용해서 파라메터 타입을 가져오려고 시도를 해봤으나 불가능했다. 왜 그럴까 생각을 해보다가 좀 더 Generic을 공부해 볼 필요를 느꼈다.


List<String> a;


이런 경우 프로그램 내에서 type parameter값이 무엇인지(String) 알아낼 방법이 없다는 것이다.

이유는 Erasure라는 것 때문이다. Java Generic은 JVM레벨의 호환성을 위해서 컴파일시에 Generic정보(<T>,<V>…)를 삭제해버린다. Generic정보가 없는 Raw Type(List)만 남는다는 것이다. -_-; 따라서 컴파일된 byte code내에는 저 <String>부분은 남아있지 않은 것이고 결국 reflection을 이용해서 그 것을 알아낼 방법이 없다. Generic은 단지 compile시에 타입체킹을 통해서 런타임시의 타입캐스팅을 보장해주는 방식으로 구현되어있다는 것이다.


이러한 백그라운드에서 일어나는 자바의 Generic구현기능 덕분에 사실 여러가지 복잡한 문제가 발생할 수 있다. 그래서 Generic은 점점 더 복잡해진다.

한가지 흥미로운 것은 모든 Generic type정보가 삭제되지 않는다는 사실! Generic의 static한 정보는 컴파일 후에도 남고 이를 런타임시에 확인해서 사용할 방법이 있다. 다만 instance를 만들거나 변수선언에 사용한 정보는 삭제된다.


** 실제로 제너릭을 이용한코드를 컴파일 한 후에 javap등과 같은 툴로 보게되면 파라미터 타입으로 처리된 변수에 대해서는 캐스팅되어 컴파일된다.

'Java > Generics' 카테고리의 다른 글

Generics in the Java  (1) 2013.02.07
Posted by Steven J.S Min
,