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 作为第一个参数。解决了这个问题,一切都对我有用。

谢谢。 马可

至少它适用于 ClassTagManifest 已弃用 - 甚至没有尝试):

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

我假设 BoundsInOneDimensionBoxId 是整数,但不要认为它会改变任何东西。 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]) 
}