scala - 如何通过反射获取Scala专用字段的参数的原始数据类型?

标签 scala reflection specialized-annotation

我有一个类,其中有一个专门的字段,并且使用原始数据类型。例如 Tuple2[Int, String]:

scala> class TupleReflection(val tuple: Tuple2[Int, String])
defined class TupleReflection

scala> val refl = new TupleReflection((5, "hello"))
refl: TupleReflection = TupleReflection@1a597ec8   

我现在想使用反射来找出“refl”实例中 Tuple2 的类型参数。 (我使用“head”来获取该字段,因为我知道这是唯一的一个。)

scala> val field = refl.getClass.getDeclaredFields.head
field: java.lang.reflect.Field = private final scala.Tuple2 TupleReflection.tuple

现在我有了可以查询泛型类型的字段。

scala> field.getGenericType
res41: java.lang.reflect.Type = scala.Tuple2<java.lang.Object, java.lang.String>

现在的问题是第一个类型是Object。有没有办法仅通过反射来了解该参数的真实类型(Int)?

更新:

我在我自己的 API 中的自动序列化上下文中使用它。给定一个标有 @Serialized 的类,我可以序列化它。为此,我必须使用反射递归地构建类的字段和类型的树,以便我可以进行深度序列化。

如果我直接使用 @Specialized 类,它会起作用,因为类型是显式的,并且在调用站点的编译时是已知的。如果层次结构中的字段是@specialized,我无法通过反射来判断。查询类中声明的字段或方法不会产生正确的值。该类型存在于运行时,但仅存在于字段中保存的实例上,而不存在于字段本身的声明上。因此,如果实例为 null 并且无法执行“getClass”,我无法仅通过反射知道正确的类型。

最佳答案

问题是您使用的 Java 反射 API 无法解决 JVM 的“类型删除”问题,因为无法用它找出实际的泛型类型。

幸运的是,即将到来的 Scala 2.10 版本实现了新的反射 API,解决了类型删除问题。但由于 2.10 尚未发布,该 API 尚未标准化或记录。您最好的选择是使用调试器等工具深入研究它,并提出此处出现的更具体的问题。

在 Scala 2.10-M5 中,您可以按如下方式访问 API:

scala> reflect.runtime.universe.typeOf[(Int, String)]
res0: reflect.runtime.universe.Type = (Int, String)

scala> reflect.runtime.universe.typeOf[(Int, String)].typeArguments
res1: List[reflect.runtime.universe.Type] = List(Int, String)

scala> reflect.runtime.universe.typeOf[(Int, String)].typeArguments.head
res2: reflect.runtime.universe.Type = Int

更新#1

以下函数展示了如何获取实例的类型:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> def typeOf[T : TypeTag](x : T) = reflect.runtime.universe.typeOf[T]
typeOf: [T](x: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type

scala> typeOf(Seq((1,"sldf"),(20,"sldkfjew")))
res0: reflect.runtime.universe.Type = Seq[(Int, String)]

事实上,它全部基于 [T : TypeTag] 部分,该部分告诉编译器神奇地创建传递类型的反射的隐式实例。

更新#2

scala> class TupleReflection(val tuple: Tuple2[Int, String])
defined class TupleReflection

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> typeOf[TupleReflection].member(newTermName("tuple")).typeSignature
res6: reflect.runtime.universe.Type = => (scala.Int, String)

scala> typeOf[TupleReflection].members
res7: Iterable[reflect.runtime.universe.Symbol] = List(constructor TupleReflection, value tuple, value tuple, method $asInstanceOf, method $isInstanceOf, method synchronized, method ##, method !=, method ==, method ne, method eq, constructor Object, method notifyAll, method notify, method clone, method getClass, method hashCode, method toString, method equals, method wait, method wait, method wait, method finalize, method asInstanceOf, method isInstanceOf, method !=, method ==)

scala> typeOf[TupleReflection].members.view.filter(_.isValue).filter(!_.isMethod).toList
res16: List[reflect.runtime.universe.Symbol] = List(value tuple)

关于scala - 如何通过反射获取Scala专用字段的参数的原始数据类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11586944/

相关文章:

scala - 模式匹配与专门的 Scala

json - CouchDB 最适合动态语言吗?

Scala:覆盖返回 null 的通用 Java 方法

scala - 斯帕克斯卡拉 : iterable to individual key-value pairs

scala - 将主题映射回 Spark LDA 中的文档

reflection - 为什么 Rebol 3 不尊重括号中的引用函数参数?

c# - 如何检查 C# 中的动态匿名类型上是否存在属性?

c# - 如何制作 "as Class",其中 Class 是字符串名称?