16 April 2001
Simon Gronlund is earning his Master of Science in Computer Science at the Royal Institute of Technology, Sweden, as an adult student. He also teaches Java and computer-related courses at the college. When he isn't tampering with his Warp 4 PC, he spends his spare time with his two boys and his wife.
If you have a comment about the content of this article, please feel free to vent in the OS/2 eZine discussion forums
Into Java, Part 16
Today we will explore a convenient way to store and retrieve your
application data, something that can be really tiresome in other programming languages, but is a breeze with Java.
In fact any data may be stored this way, basic data types or classes built by you or Java default classes. More
than that, this is a rather fast way to store and read data from disk as well as from other streams. And it is
by far the easiest technique to implement.
that resides in the
It is an empty interface that only tells the Java compiler that we know that this object may get serialized. We
need to add
to our class header. That is it, you are done!
Briefly though, when an object stream saves your object(s) it needs
to save a description of the class, further it saves a seal and some more details, I will not go into the details of
that. Important to know though, is that it is the object's state that is saved, that is, any instance variable is saved. This
is a good reason to use instance variables sparsely, many times only a few arenecessary. Think "do I need
to save this variable to get an object back on its feet again?" If the answer is "yes" it needs to be
an instance variable, but if the value may be computed from other instance variables it is not a good candidate.
Sometimes we do not want to save an instance variable in any case, perhaps
for security reasons or if it holds vital transient information. Perhaps we can ask for it or recompute
it, for example machine related information as window sizes, or a value of limited life time. In these cases we use
Since it is possible, though tiresome, to exploit
the information of the stream, it is good to use
/* a value that is useless on another machine with other screen resolutions */
private transient int windowWidth;
transient for any variable you do not want to reveal, or possibly that needs to be encrypted.
The observant reader will notice that the same reasoning must hold
for variables declared
is a class variable common to every instance of the class, while an instance variable
holds the state of a distinct object. If we need to recall the value of a static variable we need to take care
of that on our own. Having covered this use of static and transient, I consider this topic closed for now.
Finally, reading an object back from an object stream never
calls any method nor the constructor, it simply reinstates the proper values in the reincarnated object. Hence,
nothing is computed at the rebirth. If this is needed, find some deeper readings on this topic to find out
how you can do that.
xxxInt, xxxDouble, etc., (where xxx is replaced by
take care of the basic data types.
While basic data types are read and written with specific methods,
reading and writing objects is done with the
xxxObject methods. As with getting objects back from data structures, we must apply a cast to
the returned value, which is of the basic
to the type we know it should be.
If using this technique for reading and writing data one by one, it
is important that the read-back is done in exactly the same order the writing was done, using the matching methods.
When you have a lot of data, this is really tiresome. In a moment I will show you a more
There is much more to tell on this topic, but I think that will be beyond
the scope of this column. One good resource is "Core Java 2, Volume 1 ", by Horstmann & Cornell, starting at
page 664. I would like to mention that there are several ways to twist both how data and what data should be written
to the stream. Naturally in such cases we must use refined techniques to get the data back again. The door is
open, you decide your direction.
PaintBox, add two lines in the
Paintshape class. First we must import
java.io and then tell Java that we want to implement the behavior of
Serializable objects. In this class
there are no transient variables or anything else to consider.
Now we are ready with the class
PaintShape. Let us continue with
PaintPanel and see how we use object streams.
As expected, both
are located in
which needs to be imported. We will first look into
how to save our
We will simply make a stream, and then write the objects to that
stream. Add a small method
or any name you like, somewhere in the
PaintPanel class, as the figure beneath shows. We do not have to implement
Serializable in this class since this class is not going
to be saved, we are only interested in saving the painted shapes, aren't we?
If you would like to test it so far, add a single line to the
This new line will save the painting you sketched when you are exiting the program. Of course you are still not happy with that, there is no way to get the painting back. But in any case, you may find the
- find the constructor we named
- as the very first line of the
immediately before the
paint.datfile saved and you can inspect it a little. Some parts of it are readable, but most of it is not.
Please look back into the code. First we create the object output
stream, this time wrapped around a
FileOutputStream. Recall that an object stream shall be wrapped around anything extending a stream,
Kindly note that we are writing the entire
Vector storedShapes to the stream. We need not save
one shape after another or use another similar scheme, it is possible to save a complete data structure. And if it is,
for example, sorted in a certain way, upon reading it back later on, it will still be sorted in the very same way.
If there are dependencies between the stored objects, they will be valid after they are read back. Convenient,
Would you like to get the painting back? It is as simple as saving
it. Still in the
add a little method like this one.
As with the former method, we have to catch
IOException if anything goes wrong with the file.
But another exception is introduced,
ClassNotFoundException, that is thrown when a class referred to in the object file is not present
as a class file. Hence we find it necessary to always bring the class files along with the object file, they need
each other. Later on, erase the
and try to read the data file.
After creating the object input stream around a
FileInputStream we read from it. Again please note how
conveniently it is done, we simply read an object from the stream and assign the object to an instance variable
storedShapes, that is the
Vector we used when saving the painting.
Object we need to apply
a cast to a
we know that
declared to be of type
Assigning a new vector to the old variable is simply a replacement,
we replace the old data structure (a
with a new one.
Would you like to go for a test ride? Then simply add the line
as the very last line of the method
PaintBox class, after that the
paintArea object is instantiated. That is, as soon as the canvas is ready we call
readFile method which
replaces the still empty
storedShapes Vector with
a new stuffed one at start-up time. Try that, and say ... Wow!
If you followed the instructions exactly, you now can save your
paintings. Unfortunately only one, and you can not erase the data file since that will crash the program at start,
due to an
We need a better way to call the save and read methods, don't we?
Setting up a menu bar is only done once, as there is only one menu
bar in an application. The first two lines create one and set it to the frame, that is
setJMenuBar(bar) is called from within the class extending
JFrame. In our case that will be
PaintBox. I have chosen to put the
entire code within a method of its own,
which we can call from the
as the second line, between
The second part of the code is to create a menu, the "File"
menu, which we simply add to the menu bar. Having more menus is done the same way, adding each to the same menu
bar. Of course, menus may have fancy stuff like mnemonics and so forth, but I will omit that for now.
Then there is the first real menu item created, the "Open
'paint.dat'" item. So far there is nothing to worry about, but of course menus may have icons, mnemonics,
key accelerators and so forth, too. But for now we must recall how to add a listener to that item. That is
done by adding an
on the fly, supplying an
Finally we add the menu item to the menu.
Each menu item contains an
object, but it would also be fine to make the whole
implement ActionListener and
add the method
containing a few
if - if else tests
with the very same method calls. The choice is yours, and we have tested both ways in previous IntoJava installments.
As seen in the code above, we do call the two methods we created
We added two separators, for sharpness, and in order to learn how. But we have not seen the method
clearShapes that seems to be resident
PaintPanel. Here it
comes, a convenient way to start over with a new painting:
It certainly is easy with Java, isn't it? Only a single call to
removes every shape we have made, and we are ready for another sketch. Unfortunately I still do not know how to
overcome that the last item is not always cleared, but vanishes as soon as you start to paint a new object. Anyone
have an idea? Call me!.
Do not forget to remove the lines you added before when
testing the first two methods. Compile and go!
JFileChooser. At the
same time we will briefly look into the handy dialogs that come with Swing, the
As a convenience I have included all the necessary java files as they
looked before we started with this column:
We have learned how to make easy use of object streams, and that they
can handle complete data structures in a pinch. Naturally we can use these streams a lot more, and we will. We
will also, in a future column, see how convenient they are when sending data over a network, LAN or WAN.
We have also learned how to add menus to our applications, it looked
tiresome, and it sure is most of the time. But not that hard, don't you think?
CU next month.