2

我有一个要在外部存储然后恢复为原始集合类型的集合实例。例如

class Foo {
  var x : List[Int]
}

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

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

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

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

我尝试使用原始集合中可用的构建器,但我不太明白它是如何工作的,足以将其完成。

谢谢,

戴夫

4

1 回答 1

1

如果我们对您要解决的问题有更好的了解,例如为什么您不想使用标准对象序列化,那么在这里提供帮助会更容易。

也就是说,如果您真的想对 Scala 集合类进行反射,您可能需要了解一些有关 Scala 当前如何编译其类和对象的信息:

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

  • 如果您想要单例 List 对象实例,则将其存储为 field 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)
于 2010-12-01T18:11:26.717 回答