0

假设我有:

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

注意。由于 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 中可用,这样这种情况才能正确编译失败。

更新2:

想象一下,您正在编写 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 编译器正确生成类型不匹配错误(见上文)。

4

1 回答 1

1

在 java 字节码级别Int, s 必须表示为其他东西(显然Object),因为 aList只能包含对象,而不是原语。这就是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)

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

于 2015-01-07T08:39:17.660 回答