我知道番石榴的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?
谢谢!
答案 0 :(得分:3)
我认为你想要TypeTag
和typeOf
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]