可以在Scala中找到参数类型方法返回类型,其中参数是基本类型?

时间:2015-01-07 02:58:49

标签: scala reflection scala-reflect

假设我有:

class X
{
   val listPrimitive: List[Int] = null
   val listX: List[X] = null
}

我在Scala中打印出每个方法的返回类型,如下所示:

classOf[ComplexType].getMethods().foreach { m => println(s"${m.getName}: ${m.getGenericReturnType()}") }

listPrimitive: scala.collection.immutable.List<Object> 
listX: scala.collection.immutable.List<X> 

所以...我可以确定listX的元素类型是X,但有没有办法通过反射确定listPrimitive的元素类型实际上是java.lang.Integer? ...

val list:List[Int] = List[Int](123);
val listErased:List[_] = list;
println(s"${listErased(0).getClass()}")  // java.lang.Integer

NB。这似乎不是由于JVM类型擦除的问题,因为我可以找到List的types参数。看起来scala编译器抛弃了这个类型信息IFF,参数类型是java.lang。[numbers]。

更新:

由于以下实验,我怀疑此类型信息 可用。假设我定义:

class TestX{
  def f(x:X):Unit = {
    val floats:List[Float] = x.listPrimitive()  // type mismatch error
  }
}

和X.class通过jar导入。完整类型信息必须在X.class中可用,以便正确地无法编译。

UPDATE2:

想象一下,您正在为Java序列化库编写scala扩展。你需要实现一个:

def getSerializer(clz:Class[_]):Serializer

根据是否需要执行不同操作的功能:

clz==List[Int]   (or equivalently: List[java.lang.Integer])
clz==List[Float] (or equivalently: List[java.lang.Float])
clz==List[MyClass]

我的问题是我只会看到:

clz==List[Object]
clz==List[Object]
clz==List[MyClass]

因为clz是作为clz.getMethods()(i).getGenericReturnType()提供给这个函数的。

从clz开始:Class [_]如何恢复丢失的元素类型信息?

我不清楚TypeToken会帮助我,因为它的用法:

typeTag[T]

要求我提供T(即在编译时)。

所以,一个解决方案的路径......给定一些clz:Class [_],我可以确定其方法的返回类型的TypeTokens吗?显然,这是可能的,因为此信息必须包含在某个.class文件中(某处),以便scala编译器正确生成类型不匹配错误(参见上文)。

1 个答案:

答案 0 :(得分:1)

在java字节码级别Int必须表示为其他东西(显然是Object),因为List只能包含对象,而不能包含基元。这就是java级反射可以告诉你的。但是,正如您所推断的那样,scala类型信息存在(在字节码级别它是注释中的IIRC),因此您应该能够使用scala反射检查它:

import scala.reflect.runtime.universe._

val list:List[Int] = List[Int](123)

def printTypeOf[A: TypeTag](a: A) = println(typeOf[A])

printTypeOf(list)

对update2的响应:您应该使用scala反射来获取镜像,而不是Class[_]对象。如果需要,您可以通过课程名称:

import scala.reflect.runtime.universe._

val rm = runtimeMirror(getClass.getClassLoader)

val someClass: Class[_] = ...

val scalaMirrorOfClass = rm.staticClass(someClass.getName)
// or possibly rm.reflectClass(someClass) ?

val someObject: Any = ...

val scalaMirrorOfObject = rm.reflectClass(someObject)

我想如果你真的只有这个类,你可以创建一个只加载该类的类加载器吗?我无法想象你不会拥有这个类,甚至是一个值的用例。