我有一个对象
public class Foo implements Serializable {
private List<Bar> barList;
// getters and setters
}
(Bar
也实现了Serializable。)
FindBugs违反了SE_BAD_FIELD
。这是公平的,因为List
不是transient
或Serializable
。但是,我想序列化这个列表!所以我需要自己写writeObject
和readObject
。
我查看了JDK中ArrayList
writeObject
的实现,这非常简单,但也比我想象的要复杂一些。这是:
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
我曾预料到它会在上面做一个名为“按正确顺序写出所有元素”的部分。但它似乎比那复杂一点。我是否需要将这些内容复制到writeObject
内Foo
的实现中?
readObject
实现中忽略该大小。modCount
字段,有没有办法复制modCount
行为?我应该将writeObject
放在synchronized
区块内吗?谢谢!
答案 0 :(得分:1)
如果barList
是私有的并且不需要逐字设置,则快速解决方案是将其声明为private ArrayList<Bar> barList
之类的可序列化类型,并使用以下内容对其进行修改:
void addBar(Bar bar) { barList.add(bar); }
void setBarList(List<Bar> bars) { barList = new ArrayList(bars); }
但是如果由于某种原因必须自己编写序列化,则需要编写大小和每个对象(使用Externalizable,它比Serializable
更快)。基于Oracle的example:
class Foo implements Externalizable {
List<Bar> barList;
public void writeExternal(ObjectOutput out) throws IOException {
if (barList == null) {
out.writeInt(-1);
return;
}
out.writeInt(barList.size());
for (Bar bar : barList) {
out.writeObject(bar);
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
int size = in.readInt();
if (size >= 0) {
barList = new ArrayList<>();
for (int i = 0; i < size; i++) {
barList.add((Bar) in.readObject());
}
}
}
}
请注意,readExternal()
仍然使用ArrayList
。如果要保留列表的类,还可以在writeExternal()
中编写类名,并使用readExternal()
中的反射对其进行实例化。这需要在该类中使用no-args构造函数。
答案 1 :(得分:0)
FindBugs警告你,因为实际的具体List 可能不是Serializable。这并不意味着它不是。如果您确定实际列表确实在运行时可序列化(如ArrayList,LinkedList和许多其他List实现),那么您不需要做任何事情。
确保这一点的一个好方法是避免从外部接受任何List作为参数:
// ArrayList is serializable
private List<Bar> barList = new ArrayList<>();
public void setBarList(List<Bar> barList) {
// barList stays an ArrayList, still serializable
this.barList.clear();
this.barList.addAll(barList);
}