我在将对象追加到scala.collection.mutable.ListBuffer时遇到问题。我熟悉相应的API,并且知道通常您使用+ =或++ =方法添加对象或对象序列。
我正在实施具有网络支持的纸牌游戏,但有一个简单的问题,就是将一些选定的纸牌添加到手牌列表中。在下面的代码中,我将获得对手牌列表(ListBuffer)的引用,打印ListBuffer的大小,向其中添加所选卡,然后再次打印大小。
// get the references and ensure that it are rally ListBuffers / Lists
val handCards: mutable.ListBuffer[ClientCard] = playerPanel.player.handCards
val chosenCards: List[ClientCard] = _chosenCards
// print the number of elements per list
println("number of hand cards: " + handCards.size)
println("number of chosen cards: " + chosenCards.size)
// append the chosen cards to the hand cards
println("append operation: " + handCards + " ++= " + chosenCards)
handCards ++= chosenCards
// print the number of hand cards again
println("number of hand cards: " + handCards.size)
结果,人们期望,手持卡的大小将随所选卡的大小而增长。但是输出是(格式化的):
number of hand cards: 5
number of chosen cards: 2
append operation: ListBuffer(
rftg.card.Card$$anon$1@1304043,
rftg.card.Card$$anon$1@cb07ef,
rftg.card.Card$$anon$1@176086d,
rftg.card.Card$$anon$1@234265,
rftg.card.Card$$anon$1@dc1f04
) ++= List(
rftg.card.Card$$anon$1@1784427,
rftg.card.Card$$anon$1@c272bc
)
number of hand cards: 5
因此,元素尚未附加。
ClientCard始终是“真实卡”的代表,并且仅包含抽取卡所需的信息。
trait ClientCard extends AnyRef with ClientObject with CardLike
trait ClientObject extends Serializable {
def uid: Int
}
trait CardLike {
val imagePath: String
}
在Card类中创建一个ClientCard:
def clientCard = new ClientCard() {
val uid = Card.this.hashCode()
val imagePath = CardTemplate.cardFolder + Card.this.imageFilename
}
还有创建ListBuffer的ClientPlayer(“真实玩家”的代表):
// definition of ClientPlayer trait
trait ClientPlayer extends ClientObject {
val victoryPoints: Int
val handCards: mutable.ListBuffer[ClientCard]
val playedCards: mutable.ListBuffer[ClientCard]
}
// piece of code to create a client player
def clientPlayer = new ClientPlayer() {
val uid = Player.this.hashCode()
val victoryPoints = Player.this.victoryPoints
val handCards = new mutable.ListBuffer[ClientCard]
handCards ++= (Player.this.handCards.map(_.clientCard))
val playedCards = new mutable.ListBuffer[ClientCard]
playedCards ++= Player.this.playedCards.map(_.clientCard)
}
有人知道这里出了什么问题吗?或更笼统地说:在什么情况下会阻止对象成功添加到ListBuffer?
编辑:
有一些我忘记提及的东西,似乎是导致这种奇怪行为的原因。创建了HandCards ListBuffer之后,它将通过网络发送,因此将再次进行序列化和反序列化。
在Rex Kerr发表评论之后,我尝试为ClientPlayer创建一个深复制方法,并在接收到它之后立即复制每个ClientPlayer。这样就解决了问题。有人对此行为有解释吗?
最佳答案
反序列化会产生非常脆弱的ListBuffer
。这可能是一个错误,但是作为一种解决方法,您唯一需要做的就是立即将其添加到其他集合中(例如,通过toList
对其进行添加,或者将其添加至一个空的ListBuffer
中)。
您可以使用以下代码来验证序列化/反序列化是否有问题:
import collection.mutable.ListBuffer
import java.io._
val baos = new ByteArrayOutputStream
val oos = new ObjectOutputStream(baos)
oos.writeObject( ListBuffer(1,2,3) )
val bais = new ByteArrayInputStream( baos.toByteArray )
val ois = new ObjectInputStream(bais)
val lb = ois.readObject.asInstanceOf[ListBuffer[Int]]
val lb2 = ListBuffer[Int]() ++= lb
lb2 ++= List(1) // All okay
lb ++= List(1) // Throws an exception for me
我将提交一个错误报告,但是暂时您不应该依赖
ListBuffer
在反序列化时处于明智的状态,而应该重新构建它。 (您可能希望对List
进行序列化和反序列化。)