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

Tom*_*aro 2 reflection scala 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   
Run Code Online (Sandbox Code Playgroud)

我想现在使用反射来找出我的'refl'实例中的Tuple2的类型参数.(我用'头'来骗取场地,因为我知道这是唯一一个.)

scala> val field = refl.getClass.getDeclaredFields.head
field: java.lang.reflect.Field = private final scala.Tuple2 TupleReflection.tuple
Run Code Online (Sandbox Code Playgroud)

现在我有了该字段,我可以查询泛型类型.

scala> field.getGenericType
res41: java.lang.reflect.Type = scala.Tuple2<java.lang.Object, java.lang.String>
Run Code Online (Sandbox Code Playgroud)

现在的问题是第一种类型是Object.有没有办法通过单独的反射知道该参数的实际类型(Int)?

更新:

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

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

Nik*_*kov 5

问题是您使用的是Java反射API,它不能解决JVM的"类型擦除"问题,因为没有办法找出它的实际泛型类型.

幸运的是,即将推出的2.10版Scala实现了新的反射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
Run Code Online (Sandbox Code Playgroud)

更新#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)]
Run Code Online (Sandbox Code Playgroud)

事实上,它都是基于[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)
Run Code Online (Sandbox Code Playgroud)