获取包含ClassTag的泛型类型

时间:2015-01-06 18:01:28

标签: java scala reflection types guava

我知道番石榴的TypeToken能够做到这一点:

class C[I, O]    

class A[T] {
  val tok = new TypeToken[T](getClass){}
}

val a = new A[C[Integer, String]]{}
println(a.tok)  // somepackage.C<java.lang.Integer, java.lang.String>

但是对于scala的ClassTag,我得到了:

class B[T: ClassTag] {
  // runtime class
  val clazz = implicitly[ClassTag[T]].runtimeClass
  // also tries to construct a guava type token
  val tok = TypeToken.of(clazz).asInstanceOf[TypeToken[T]]
}

val b = new B[C[Integer, String]]
println(b.clazz)  // class somepackage.C
println(b.tok)    // somepackage.C

因此,对于ClassTag,C所包含的遗传类型会丢失。是否可以在Scala中使用ClassTag或其他东西获得somepackage.C?

谢谢!

2 个答案:

答案 0 :(得分:3)

我认为你想要TypeTagtypeOf

import scala.reflect.runtime.universe._

class C[I, O]

class A[T: TypeTag] {
  val tpe = typeOf[T]
}

val a = new A[C[Integer, String]]
println(a.tpe) // C[java.lang.Integer,String]

答案 1 :(得分:1)

TypeToken做了一个有趣的伎俩。让我们说你有这个:

class A[T]
class B extends A[String]

尽管Java在运行时擦除了类型参数,但B的超类不是A[T],而是A[String]。该信息被保留,并且可以获得。所以当你这样做时:

val tok = new TypeToken[T](getClass){}

最后的{}表示您正在创建TypeToken匿名子类,其中一个嵌套在A[T]上,因此{的每个实例都是A[T] {1}}实际上会产生一个不同的匿名子类。

无论如何,这是基本思想,它取决于嵌套在参数化类中的匿名子类。只有ClassTag(主要是Class的包装)并不够好。

Scala 可以使用TypeTag保留完整的类型信息,但这会带来成本。 Scala的类型系统相当复杂,比Java更复杂,因此,保留完整类型信息需要大量代码。

因此,ClassTag(主要依赖于Java捆绑的Class)与scala-library一起提供,而使用TypeTag则需要添加scala-reflect你的依赖项,在Scala 2.11.4上约为4.2MB。

然而,一旦你有了这个,其余的都是微不足道的,如lmm所示(无耻的复制和粘贴来自他的answer):

import scala.reflect.runtime.universe._

class C[I, O]

class A[T: TypeTag] {
  val tpe = typeOf[T]
}

val a = new A[C[Integer, String]]
println(a.tpe) // C[java.lang.Integer,String]