I am confused about this.
Since when doing implementation of Serializable class, we need to use classes like FileOutputStream
, ObjectOutputStream
or something like that. Then why not we just use those classes to do things like output a object to a file and input a object from a file to maintain the status of a object directly? Why should we first implement Serializable and then do the same thing?
问题:
回答1:
Understand it like this...
Serializable is marker interface which denotes that the object of your class can be converted into byte stream and eventually back into java object if required. Initially you might think that every class should be serializable but that's not correct consider
Input- and OutputStreams which have some file handle to read from. That file handle is closed when the stream becomes unavailable. So serialization at this instance doesn't make sense; and de-serialization would never restore that handle.
So this should answer why marking as Serializable is required?
Now implementing methods which define how your object should be written or read; that should be defined by you and hence you need all those stream objects and readObject, writeObject methods. Hope this gives you a bit more understanding of this concept.
回答2:
Serializable is just a marker interface, meaning that it is just used to signal to the code that will actually do the serialization that you (the programmer) know (or hope :-)) that this class can be serialized without issues.
Serialization itself is the conversion of an object into something that can be stored or transmitted - that is, as a stream of bytes. You can compare serialization to freezedrying, the technique used to make Nescafe - all the water is removed and only the coffee essence is stored in a jar - only an obect's state (field values) gets converted into a bytestream, not its methods.
回答3:
As fvu already stated, serialization is the process of transforming an instance of a class into an array of bytes and viceversa. Not every class in Java can be transformed into an array of bytes (think about the Thread
class, it just doesn't make sense to transform a thread into an array of bytes) and that's the reason you (and us) need to implement the Serializable
in those objects that CAN be transformed.
Serializable
is just a marker interface, it doesn't require any methods to be implemented. In most cases this is good enough: just make your serializable object implement the interface and then use the default behaviour.
That default serialization behaviour is implemented in the ObjectInputStream
and ObjectOutputStream
classes. FileInputStream
and FileOutputStream
are different classes which are meant to read and write data from files on disk.
If you want to write an object to disk you need use something like this:
MyObject obj = ... // your object instance
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("/path/to/file"));
stream.writeObject(obj);
To read the object back then you need this:
ObjectInputStream stream = new ObjectInputStream(new FileInputStream("/path/to/file"));
MyObject obj = (MyObject) stream.readObject();
But sometimes you'll want to serialize/deserialize an object instance into memory, not disk, then you'll use something like this:
MyObject obj = ... // your object instance
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
byte[] data = baos.toByteArray();
I'll omit the part of reading the object back from the byte array as it's quite straightforward but think in the huge combinations that you may use will all the different input/output streams provided by the JVM.
Examples above use the default serialization behaviour. However, you may face scenarios in which a given class that you want to serialize contains references to other class instances which don't implement the Serializable
interface so, how do we serialize them? We need to mark those references with the transient
modifier so the default serialization behaviour will ignore them and we need to override the default behaviour providing private readObject
and writeObject
methods that will be invoked when trying to serialize/deserialize your object instance.
Additionally, some classes may provide a replacement object (an object instance of a different serializable class) when serialization occurs. That replacement object would contain the state of the original class in way in which that original class can be restored from that replacement object. This behaviour is implemented providing a writeReplace
method in the original class and a readReplace
in the replacement class. Please note that both, original and replacement classes have to implement the Serializable
interface but just the data in the replacement object will get serialized.
Last but not least there is the option to completely override the default serialization protocol implementing the Externalizable
interface. This is not a marker interface as Serializable
is and you must implement the methods to transform your object's state into an array and viceversa. You'll be still using the ObjectInputStream
/ObjectOutputStream
pair to serialize (externalise??) externalizable object instances but now the logic to transform your class into an array of bytes is no longer the one provided by the JVM but the one you wrote in your class when implementing the Externalizable
class.
All this information is in the link that thinksteep provided as a comment.
回答4:
Serialization is the process of taking an object and write it to a byte array (later read from byte array to object)
ObjectOutputStream uses serialization inside, it turns the object to byte[] using serialize and writes it to its output