Как я могу рефлексивно создать новую коллекцию? - PullRequest
2 голосов
/ 01 декабря 2010

У меня есть экземпляр коллекции, которую я хочу сохранить снаружи, а затем восстановить обратно в исходный тип коллекции.Например,

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) Я не хочу использовать "стандартную" сериализацию

Я пробовалиспользовать конструкторов, доступных на оригинальной коллекции, но я не совсем понимаю, как это работает достаточно, чтобы осуществить это.

Спасибо,

Дейв

1 Ответ

1 голос
/ 01 декабря 2010

Было бы легче помочь, если бы у нас было лучшее представление о проблеме, которую вы пытаетесь решить, например, почему вы не хотите использовать стандартную сериализацию объектов.

Тем не менее, еслиВы действительно хотите поразмышлять над классами коллекций Scala, вам, вероятно, нужно знать несколько вещей о том, как Scala в настоящее время компилирует свои классы и объекты:

  • Если вы хотите, чтобы классобъект List (не для класса List), имя scala.collection.immutable.List$ - обратите внимание на последний знак доллара.

  • Если вам нужен экземпляр объекта Listton, который хранится как поле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)
...