2013년 1월 19일 토요일

Scala 의 reflection 을 이용한 객체 생성

리플렉션을 공부할 때, 가장 먼저 해보는 것이 수형을 이용하여 기본 생성자를 통한 객체를 생성해 보는 것입니다.
java에서는 당연히 가능하고, 아주 쉽습니다. java 의 generic이 . NET과는 달리 JVM 상에서는 타입을 지워버리는 (erasure) 특성때문에 적응하는데 좀 애를 먹었습니다. ㅋㅋ


그럼 Scala에서는? 다행히 Scala 2.10.0 부터는 scala.reflect.runtime.unverse.TypeTag 로 더 많은 기능을 제공하지만, 기존 2.9.2 버전에서도 지원하는 scala.reflect.ClassTag 를 이용하면 java와는 달리 .NET처럼 수형을 제공하지 않아도 동적으로 수형을 알아낼 수 있더군요.


와 같이 기본 생성자를 가진 클래스는 손쉽게 생성할 수 있습니다.
좀 더 나가서 기본 생성자 이외에 인자가 있는 클래스의 경우 인자를 주고 생성하는 경우는 어떨까? 제작해 보았습니다.

인자가 있는 경우는 인자로부터 수형을 추출하여, 해당 수형들을 인자로 받을 수 있는 생성자를 찾습니다.
추출한 생성자에게 인자들을 제공하여 생성하면 됩니다.


여기서 문제가 발생했습니다... java의 primitive type인 boolean, char, byte, short, int, long, float, double 이 문제였습니다. Scala가 boxing, unboxing 을 최소화하기위해 scala.Int, scala.Long 등의 수형을 정의하여 자동으로 (implicit) 하게 변환이 되도록 하였습니다. 이러한 기능으로 JVM 에서 구현될 때 scala.Int, scala.Long 등을 java 의 primitive type 으로 매칭시켜줘야 합니다.


이 변환 메소드를 써야 제대로 실행됩니다.

마지막으로, 아예 생성자의 수형까지 지정해서 생성자를 찾을 수 있도록 하면 다음과 같습니다.

자 이제 구현한 메소드를 이용하여 실제 테스트 코드를 제작하면 다음과 같습니다.



Scala가 Generic 에서는 Java 보다 .NET에 유사하여 이해하기도 쉽고, 더 쉽게 적용이 가능하다고 생각되네요.

위에서 사용한 ClassTag[T] 의 단점은 Nested Class 에 대해서는 지원하지 않습니다. 내부 Class 도 지원하려면 TypeTag[T]  로 해야 합니다.

댓글 없음: