我如何反思地创建一个新的集合?

时间:2010-12-01 04:04:57

标签: scala scala-collections

我有一个集合的实例,我想在外部存储,然后还原回原始集合类型。例如

class Foo {
  var x : List[Int]
}

val f = new Foo
f.x = List(1, 2, 3)

我“序列化”了f,我想反思地创建一个新的Foo,f2,并用正确的结果填充f2.x.

我可以通过classOf[Foo].newInstance创建新的Foo,但是如何创建正确的集合类型并填充它呢?

注意,我在这里做了很多假设,值得注意的是:   1)我知道f.x的类型,我甚至可以序列化它的类型   2)我将x的内容序列化为保留值的东西   3)我不想使用任何“标准”序列化

我已经尝试使用原始集合中可用的构建器,但我不太明白它是如何工作的,以便将它拉下来。

谢谢,

戴夫

1 个答案:

答案 0 :(得分:1)

如果我们更好地了解您要解决的问题,例如,这将更容易帮助。为什么你不想使用标准对象序列化。

那就是说,如果你真的想对Scala集合类进行反思,你可能需要了解一些关于Scala当前如何编译其类和对象的事情:

  • 如果您想要List对象的类(不是List类),则名称为scala.collection.immutable.List$ - 请注意最终的美元符号。

  • 如果您需要单例列表对象实例,则将其存储为字段MODULE$

  • 大多数scala集合伴随对象提供newBuilder方法,该方法创建一个具有+=$plus$eq)方法和result方法的对象,创建一个新的集合。

所以你可以这样做:

scala> def buildByReflection[T](collectionClassName: String, items: Array[T]) = {
     |   val companionClass = Class.forName(collectionClassName + "$")
     |   val companion = companionClass.getField("MODULE$").get(null)
     |   val newBuilder = companionClass.getMethod("newBuilder")
     |   val builder = newBuilder.invoke(companion)
     |   val plusEq = builder.getClass.getMethod("$plus$eq", classOf[Object])
     |   for (item <- items) {
     |     plusEq.invoke(builder, item.asInstanceOf[AnyRef])
     |   }
     |   builder.getClass.getMethod("result").invoke(builder)
     | }
buildByReflection: [T](collectionClassName: String,items: Array[T])java.lang.Object

scala> buildByReflection("scala.collection.immutable.List", Array(1, 2, 3))
res0: java.lang.Object = List(1, 2, 3)