可以在 Scala 中找到参数类型方法 return 类型,其中参数是原始类型吗?
Possible to find parameter type methods return type in Scala where parameter is a primitive type?
假设我有:
class X
{
val listPrimitive: List[Int] = null
val listX: List[X] = null
}
然后我打印出 Scala 中每个方法的 return 类型如下:
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 的类型参数。看起来 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[_],我可以确定其方法的 return 类型的 TypeTokens 吗?显然这是可能的,因为此信息必须包含(某处)在 .class 文件中,以便 scala 编译器正确生成类型不匹配错误(见上文)。
在 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[_]
对象。如果需要,您可以通过 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)
我想如果你真的只有class,你可以创建一个只加载class的class加载器?不过,我无法想象没有 class 甚至没有值的用例。
假设我有:
class X
{
val listPrimitive: List[Int] = null
val listX: List[X] = null
}
然后我打印出 Scala 中每个方法的 return 类型如下:
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 的类型参数。看起来 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[_],我可以确定其方法的 return 类型的 TypeTokens 吗?显然这是可能的,因为此信息必须包含(某处)在 .class 文件中,以便 scala 编译器正确生成类型不匹配错误(见上文)。
在 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[_]
对象。如果需要,您可以通过 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)
我想如果你真的只有class,你可以创建一个只加载class的class加载器?不过,我无法想象没有 class 甚至没有值的用例。