简体   繁体   中英

How should I read and write an object containing a List in java?

I had an object

public class Foo implements Serializable {
    private List<Bar> barList;
    // getters and setters
}

( Bar also implements Serializable.)

FindBugs threw a violation SE_BAD_FIELD . Which is fair enough, because List is not transient or Serializable . However, I want to serialize this list! So I'm going to need to write writeObject and readObject myself.

I had a look at the ArrayList implementation of writeObject in the JDK, which is fairly straightforward but also a little more complicated than I thought. Here it is:

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();
    }
}

I had expected it would just do the part called "Write out all elements in the proper order" above. But it seems to be a bit more complex than that. Do I need to copy the stuff into my implementation of writeObject inside Foo ?

  • Do I need to call default write if I am going to be generating a new ArrayList to write the objects into? The private fields of the list itself probably don't need to be retained.
  • What is the point of writing the size separately, when the size will be written in the default write? The size is ignored in the corresponding readObject implementation.
  • Is there any way for me to replicate the modCount behaviour given that I don't have access to the protected modCount field? Should I put writeObject inside a synchronized block?

Thanks!

If barList is private and doesn't need to be set verbatim, a quick solution is to declare it as some serializable type like private ArrayList<Bar> barList and modify it with something like:

void addBar(Bar bar) { barList.add(bar); }
void setBarList(List<Bar> bars) { barList = new ArrayList(bars); }

But if you have to write serialization yourself for some reason, you need to write the size and each object (use Externalizable , it's faster than just Serializable ). Based on example from Oracle:

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());
      }
    }
  }
}

Note that readExternal() still uses ArrayList . If you want to preserve the class of the list, you can also write class name in writeExternal() and instantiate it using reflection in readExternal() . That would require a no-args constructor in that class though.

FindBugs is warning you, because the actual concrete List might not be Serializable. That doesn't mean it isn't. If you're absolutely sure that the actual list is indeed, at runtime, serializable (as ArrayList, LinkedList and many other List implementations are), then you don't need to do anything.

A good way to ensure about that is to avoid accepting any List as argument from the outside:

// 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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM