我可以使用Scala TypeTags和ClassTags来遍历没有实例的对象模型吗?

时间:2016-07-10 00:02:28

标签: scala

我的目标是通过遍历其类来使用对象模型的结构。这在Java中是不可能的,因为擦除会阻止我在运行时知道集合的元素类型。我还不太了解ClassTags和TypeTags。有没有办法使用它们来复活集合的元素类型,即使我没有访问实例?

更新:对我来说,这个问题的一个组成部分是我想要检查任意JavaBeans,并且没有预先列出可能的输入类。我见过使用TypeTags的例子似乎总是为在编译时显式命名的类创建一个TypeTag。我是否可以使用类型标签来确定集合的元素类型,而不具有可能的元素类型的先验列表?

1 个答案:

答案 0 :(得分:0)

有几种方法:

1)运行时。由于擦除,JVM失去了有关多态类型(泛型)的信息,但是如果你需要对象的那种反射,你可以介绍你可以使用typeTag作为你的根对象然后更深入了:

def getReflectedType[T: TypeTag](val object: T)= typeTag[T]
val m = runtimeMirror(getClass.getClassLoader)

case class Aaa[T](a: T)
case class Bbb[T](l: List[T])
val a = Bbb(List.empty[Aaa[Int]])

所以在这里你可以访问该信息:

scala> getReflectedType(a).tpe
res35: reflect.runtime.universe.Type = Bbb[Aaa[Int]]

scala> getReflectedType(a).tpe.foreach(println)
Bbb[Aaa[Int]]
$line58.$read.$iw.$iw.$iw.$iw.type
$line58.$read.$iw.$iw.$iw.type
$line58.$read.$iw.$iw.type
$line58.$read.$iw.type
$line58.$read.type
$line58.type
<root>
Aaa[Int]
$line59.$read.$iw.$iw.$iw.$iw.type
$line59.$read.$iw.$iw.$iw.type
$line59.$read.$iw.$iw.type
$line59.$read.$iw.type
$line59.$read.type
$line59.type
<root>
Int
scala.type

所以你基本上可以访问该信息。

有些助手可能会有用:

scala> getReflectedType(a).tpe.typeSymbol.asClass
res55: reflect.runtime.universe.ClassSymbol = class Bbb

为您提供具有API的ClassSymbol(请注意,它们几乎将分割功能分配给某些单独的API,因此如果您看到没有任何成员的反射实体,请尝试查找EntityApi):

http://www.scala-lang.org/api/2.11.0-M4/index.html#scala.reflect.api.Symbols $ ClassSymbolApi

scala> getReflectedType(a).tpe.declarations.toList.map(_.typeSignature)
warning: there was one deprecation warning; re-run with -deprecation for details
res67: List[reflect.runtime.universe.Type] = List(=> scala.List[T], scala.List[T], (l: scala.List[T])Bbb[T], [T](l: scala.List[T])Bbb[T], [T]=> scala.List[T] @scala.annotation.unchecked.uncheckedVariance, => java.lang.String, => scala.Int, (x$1: scala.Int)scala.Any, => Iterator[scala.Any], (x$1: scala.Any)scala.Boolean, ()scala.Int, ()java.lang.String, (x$1: scala.Any)scala.Boolean)

scala> getReflectedType(a).tpe.declarations.toList.map(x => x.name -> x.typeSignature).mkString("\n")
warning: there was one deprecation warning; re-run with -deprecation for details
res69: String =
(l,=> scala.List[T])
(l ,scala.List[T])
(<init>,(l: scala.List[T])Bbb[T])
(copy,[T](l: scala.List[T])Bbb[T])
(copy$default$1,[T]=> scala.List[T] @scala.annotation.unchecked.uncheckedVariance)
(productPrefix,=> java.lang.String)
(productArity,=> scala.Int)
(productElement,(x$1: scala.Int)scala.Any)
(productIterator,=> Iterator[scala.Any])
(canEqual,(x$1: scala.Any)scala.Boolean)
(hashCode,()scala.Int)
(toString,()java.lang.String)
(equals,(x$1: scala.Any)scala.Boolean)

为你提供成员的类型签名,我找不到方便的apy来匹配签名到type-parameter,所以你必须手动完成(asSeenFrom可能有帮助)。

2)编译时间。当你在函数中得到它时,你可能不知道完整的结构类型。因此,您可以使用WeakTypeTag宏。它将提供尽可能多的信息。