Scala 反射和泛型
Scala reflection and generics
我遇到了 Scala 反射和泛型的问题。我有一个摘要 class 有这个签名:
IPartition [T <: IPartition[T]] (val bounds: Array[BoundsInOneDimension],
val boxId: BoxId = 0, val partitionId: Int = -1, var adjacentPartitions: List[T] = Nil)
和具有此签名的具体 class:
Box (bounds: Array[BoundsInOneDimension], boxId: BoxId = 0, partitionId: Int = -1, adjacentBoxes: List[Box] = Nil)
extends IPartition[Box] (bounds, boxId, partitionId, adjacentBoxes)
我想做的是在 object
的泛型方法中实例化具体的 class。因此,我有这个方法:
myMethod[SHAPE <: IPartition[SHAPE]] (...) (implicit m:Manifest[SHAPE]): Iterable[SHAPE]
并且在这个方法中我需要实例化通用 class SHAPE 扩展上面的抽象 class。
到目前为止,我已经尝试这样做了:
m.getClass.getConstructors.apply(0).newInstance(combinations(i).reverse , Int.box(i+1), Int.box(-1)).asInstanceOf[SHAPE]
但是我得到了 java.lang.IllegalArgumentException
。然后我打印了构造函数期望的参数,它们是:
class scala.Option
class java.lang.Class
class scala.collection.immutable.List
而且我无法理解这一点。我期望有 4 个参数,或者 1 个,或者类似的东西。此外,我没想到 scala.Option
作为第一个参数,也没有 java.lang.Class
作为第二个参数。
我不明白如何使用正确的参数正确实例化我需要的 class。有人可以帮助我吗?
* 更新 *
现在,我已经尝试根据@dk14 的回复
for (i <- 0 until combinations.size) yield classTag.runtimeClass.getConstructors.apply(0).newInstance(combinations(i).reverse , Int.box(i+1), Int.box(-1), Nil:List[SHAPE]).asInstanceOf[SHAPE]
我得到了 java.lang.IllegalArgumentException: argument type mismatch
。我不明白我错过了什么...
* 更新 2 *
在这种情况下,我的问题很愚蠢。问题是我传递的是 List
而不是 Array
作为第一个参数。解决了这个问题,一切都对我有用。
谢谢。
马可
至少它适用于 ClassTag
(Manifest
已弃用 - 甚至没有尝试):
import scala.reflect._
scala> def myMethod[SHAPE <: IPartition[SHAPE]: ClassTag] (bs: Object, bi: Object, p: Object, a: Object) = classTag[SHAPE].runtimeClass.getConstructors()(0).newInstance(bs, bi, p, a)
myMethod: [SHAPE <: IPartition[SHAPE]](bs: Object, bi: Object, p: Object, a: Object)(implicit evidence: scala.reflect.ClassTag[SHAPE])Any
scala> myMethod[Box](Array(1,2,3), 1: Integer, 1: Integer, List[Box]())
res27: Any = Box@3305055b
我假设 BoundsInOneDimension
和 BoxId
是整数,但不要认为它会改变任何东西。 Scala 2.11.2 在这里。
这里是getConstructors()(0).getParameterTypes()
:
Array(class [I, int, int, class scala.collection.immutable.List) //`class [I` means Array of integers
您也可以使用 TypeTag
和 Scala 反射(而不是 Java 的),后者类型安全性更高 - How to get constructor arguments in a method using typetags/mirrors?。像那样:
def creator[T <: IPartition[T] : TypeTag]() = {
val m = ru.runtimeMirror(getClass.getClassLoader)
val classType = ru.typeOf[T].typeSymbol.asClass
val constructor = typeTag[T].tpe.declaration(ru.nme.CONSTRUCTOR).asMethod
val constructorMethod = m.reflectClass(classType).reflectConstructor(constructor)
constructorMethod.apply(Array.empty[Int],2,3,List.empty[Box])
}
我遇到了 Scala 反射和泛型的问题。我有一个摘要 class 有这个签名:
IPartition [T <: IPartition[T]] (val bounds: Array[BoundsInOneDimension],
val boxId: BoxId = 0, val partitionId: Int = -1, var adjacentPartitions: List[T] = Nil)
和具有此签名的具体 class:
Box (bounds: Array[BoundsInOneDimension], boxId: BoxId = 0, partitionId: Int = -1, adjacentBoxes: List[Box] = Nil)
extends IPartition[Box] (bounds, boxId, partitionId, adjacentBoxes)
我想做的是在 object
的泛型方法中实例化具体的 class。因此,我有这个方法:
myMethod[SHAPE <: IPartition[SHAPE]] (...) (implicit m:Manifest[SHAPE]): Iterable[SHAPE]
并且在这个方法中我需要实例化通用 class SHAPE 扩展上面的抽象 class。
到目前为止,我已经尝试这样做了:
m.getClass.getConstructors.apply(0).newInstance(combinations(i).reverse , Int.box(i+1), Int.box(-1)).asInstanceOf[SHAPE]
但是我得到了 java.lang.IllegalArgumentException
。然后我打印了构造函数期望的参数,它们是:
class scala.Option
class java.lang.Class
class scala.collection.immutable.List
而且我无法理解这一点。我期望有 4 个参数,或者 1 个,或者类似的东西。此外,我没想到 scala.Option
作为第一个参数,也没有 java.lang.Class
作为第二个参数。
我不明白如何使用正确的参数正确实例化我需要的 class。有人可以帮助我吗?
* 更新 *
现在,我已经尝试根据@dk14 的回复
for (i <- 0 until combinations.size) yield classTag.runtimeClass.getConstructors.apply(0).newInstance(combinations(i).reverse , Int.box(i+1), Int.box(-1), Nil:List[SHAPE]).asInstanceOf[SHAPE]
我得到了 java.lang.IllegalArgumentException: argument type mismatch
。我不明白我错过了什么...
* 更新 2 *
在这种情况下,我的问题很愚蠢。问题是我传递的是 List
而不是 Array
作为第一个参数。解决了这个问题,一切都对我有用。
谢谢。 马可
至少它适用于 ClassTag
(Manifest
已弃用 - 甚至没有尝试):
import scala.reflect._
scala> def myMethod[SHAPE <: IPartition[SHAPE]: ClassTag] (bs: Object, bi: Object, p: Object, a: Object) = classTag[SHAPE].runtimeClass.getConstructors()(0).newInstance(bs, bi, p, a)
myMethod: [SHAPE <: IPartition[SHAPE]](bs: Object, bi: Object, p: Object, a: Object)(implicit evidence: scala.reflect.ClassTag[SHAPE])Any
scala> myMethod[Box](Array(1,2,3), 1: Integer, 1: Integer, List[Box]())
res27: Any = Box@3305055b
我假设 BoundsInOneDimension
和 BoxId
是整数,但不要认为它会改变任何东西。 Scala 2.11.2 在这里。
这里是getConstructors()(0).getParameterTypes()
:
Array(class [I, int, int, class scala.collection.immutable.List) //`class [I` means Array of integers
您也可以使用 TypeTag
和 Scala 反射(而不是 Java 的),后者类型安全性更高 - How to get constructor arguments in a method using typetags/mirrors?。像那样:
def creator[T <: IPartition[T] : TypeTag]() = {
val m = ru.runtimeMirror(getClass.getClassLoader)
val classType = ru.typeOf[T].typeSymbol.asClass
val constructor = typeTag[T].tpe.declaration(ru.nme.CONSTRUCTOR).asMethod
val constructorMethod = m.reflectClass(classType).reflectConstructor(constructor)
constructorMethod.apply(Array.empty[Int],2,3,List.empty[Box])
}