Java Reference
In-Depth Information
Although the previous code fragment works perfectly well, it does not result in a stream that is partic-
ularly efficient because the output stream returned by
newOutputStream()
is unbuffered, so each output
operation writes directly to the file. In practice you probably want to buffer write operations to the file in
memory, in which case you would create the
ObjectOutputStream
object between the
try
block paren-
theses like this:
try(ObjectOutputStream objectOut =
new ObjectOutputStream(new BufferedOutputStream(
Files.newOutputStream(file)))) {
...
} catch(IOException e) {
e.printStackTrace();
}
The
BufferedOutputStream
constructor creates an object that buffers the
OutputStream
object that is
passed to it, so here you get a buffered
OutputStream
object for the file that you pass to the
ObjectOut-
putStream
constructor. The
BufferedOutputStream
object writes the data to an internal buffer. Data from
the buffer is written to the file whenever the buffer is full, or when the stream is closed. By default, the buffer
has a capacity of 2048 bytes. If you want to use a buffer of a different size, you can use the
BufferedOut-
putStream
constructor that accepts a second argument of type
int
that defines the size of the buffer in
bytes.
To write an object to the file, you call the
writeObject()
method for
objectOut
with a reference to
the object to be written as the argument. Because this method accepts a reference of type
Object
as an ar-
gument, you can pass a reference of any class type to the method and this includes
enum
types and arrays.
Three basic conditions have to be met for an object to be written to a stream:
• The class must be declared as
public
.
• The class must implement the
Serializable
interface.
• If the class has a direct or indirect base class that is not serializable, then that base class must have
a default constructor — that is, a constructor that requires no arguments. The derived class must
take care of transferring the base class data members to the stream. I'll explain how a little later in
this chapter.
It is also very desirable that the class defines a member of type long with the name
serialVersionUID
.
For example, you could define the member of the class like this:
private static final long serialVersionUID = 9002L;
This defines the member as
private
, but any access modifier is acceptable. This variable identifies a
version number for the class that is used to verify that the same class definition is used during the deserializ-
ation process when objects are read from the file as when objects were written to the file. The specific value
you assign to the
serialVersionUID
variable is not important. What is important is that you change the
value if you modify the class definition, which ensures that using the incorrect version of the class to read
objects from a file is flagged. Other than this, implementing the
Serializable
interface is a lot less difficult
than it sounds; you see how in a moment. I come back to the question of how to deal with a non-serializable
base class later in this chapter.
If
myObject
is an instance of a public class that implements
Serializable
, then to write
myObject
to
the stream that you defined previously, you use the following statement: