Scala反射和泛型

时间:2015-04-11 07:45:15

标签: scala generics reflection

我正面临着Scala反射和泛型的问题。我有一个抽象类,它有这个签名:

IPartition [T <: IPartition[T]] (val bounds: Array[BoundsInOneDimension], 
val boxId: BoxId = 0, val partitionId: Int = -1, var adjacentPartitions: List[T] = Nil) 

以及具有此签名的具体类:

Box (bounds: Array[BoundsInOneDimension], boxId: BoxId = 0, partitionId: Int = -1, adjacentBoxes: List[Box] = Nil) 
extends IPartition[Box] (bounds, boxId, partitionId, adjacentBoxes)

我想做的是在object的通用方法中实例化具体类。因此,我有这个方法:

myMethod[SHAPE <: IPartition[SHAPE]] (...) (implicit m:Manifest[SHAPE]): Iterable[SHAPE]

并且在这个方法中我需要实例化扩展上面抽象类的泛型类SHAPE。

到现在为止,我已经尝试过这样做了:

 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也不是第二个参数。

我无法理解如何使用正确的参数正确实例化我需要的类。愿任何人帮助我吗?

*更新*

现在,我已尝试根据@ 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作为第一个参数。修正了这一切,一切都对我有用。

感谢。 马可

1 个答案:

答案 0 :(得分:2)

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

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$1: 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 Reflection(而不是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]) 
}