问题
I was reading the Wikipedia article on DD and jumped over to the "Double dispatch in Java and an example" link given at the end. The description of the following Serializable example seems rather confusing to me:
A a = new A();
ObjectOutputStream oos = new ObjectOutputStream();
oos.writeObject( a);
Here's the description:
In order to serialize A,
ObjectOutputStream
first looks to see if the methodwriteObject( ObjectOutputStream oos)
exists. If it does, then it calls that method with itself as an argument. ThewriteObject
method then dispatches the call back to theObjectOutputStream
(thus making this a double dispatch). In making this very simple call back,ObjectOutputStream
has said: "I'm delegating back to you the responsibility of writing your state onto this stream". In making that simple choice,ObjectOutputStream
has decoupled itself from our objectA
. ObjectA
in turn says ok, here is some state that I want written on the stream. If the value is a primitive, then it can be dealt by the overloading of the write method. If not, the back and forth can continue at the next level down in the objects graph until all of the useful state has been placed on the stream.
I'm guessing that the description might be confusing because what is being described is what is happening behind the scenes and not the code presented because otherwise it doesn't seem to make much sense. Here are the parts that confuse me:
- "
ObjectOutputStream
first looks to see if the methodwriteObject( ObjectOutputStream oos)
exists". Why wouldObjectOutputStream
need to check for the existence of this method since it is its own method? - "If it does, then it calls that method with itself as an argument". It looks to me like it's calling
writeObject
with an instance ofA
as an argument. Going back to the previous item, why would it look for thewriteObject
signature with anObjectOutputStream
arg if it's being called with an instance ofA
? - "The
writeObject
method then dispatches the call back to theObjectOutputStream
(thus making this a double dispatch)". Again, thewriteObject
method belongs to theObjectOutputStream
class so I fail to see how this gets "dispatched back to theObjectOutputStream
" since that appears to be the original destination.
Am I just missing something fundamental here or is this a poorly written/described example? If it is a bad example, I'd like to change the Wikipedia article to point to a better one so feel free to provide suggestions.
Thanks.
回答1:
To answer your questions in order:
ObjectOutputStream.writeObject(Object)
checks its argument (using reflection) to determine if the object implementswriteObject(ObjectOutputStream)
. That is, it more or less asks the object, "Do you know how to write your structure to anObjectOutputStream
?"If the answer is "yes", then the
ObjectOutputStream
calls the object'swriteObject(ObjectOutputStream)
method, passing itself (theObjectOutputStream
, not the object) as the argument. It basically says, "Good. Write your structure to me."The implementation of
writeObject(ObjectOutputStream)
in the object calls on theObjectOutputStream
to write elements of itself. It is not supposed to calloos.writeObject(this)
again.
For example, suppose I had an object like this:
class A {
int x;
}
If I wanted to enable it to write itself to an ObjectOutputStream
, I might expand it like this:
class A implements Serializable {
int x;
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.writeInt(x);
}
}
Then this code:
A a = new A();
ObjectOutputStream oos = . . .;
oos.writeObject(a);
would use the writeObject
method in class A
to write a
, rather than using reflection to write all the (non-transient) fields of A. (In this case, however, there would be no difference.)
回答2:
From the documentation of the Serializable interface:
Classes that require special handling during the serialization and deserialization process must implement special methods with these exact signatures:
private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException;
If you want to make your class serializable implementing the interface is enough. But, if you want make the object (of the class) itself tell the output stream how to serialize it's own state then it should implement those methods.
来源:https://stackoverflow.com/questions/13151524/double-dispatch-in-java-example