We have seen that Java is very strict with data
types. Every data element must be explicitly assigned to a specific
type. Casting can convert
data of one type into another but a data value can never simultaneously
act as more than one type. This differs from C/C++ where, say,
a 32-bit integer type value can easily be accessed as two short
values or four separate bytes.
For binary I/O with files as discussed previously,
the underlying flow of data occurs as a sequence of bytes. We
saw that by wrapping FileOutputStream
with a DataOutputStream
we obtained methods such as writeInt
(int) and writeDouble
(double) that put the bytes of wider types like int
or double
onto the outgoing stream.
Similarly, by wrapping a FileInputStream
with a DataInputStream,
the readInt()
and readDouble()
methods convert four bytes in the stream into an int
value and eight bytes into a double
value, respectively.
Note that on all platforms, Java uses the so-called
big-endian representation. This means that for any primitive
data value longer than one byte, the most significant byte is
at the lowest address (i.e. big end first.) So, for example, in
an output stream of int
values, the high order byte goes out first and in an input stream
the high order byte arrives first. This order is preserved by
the JVM even on underlying platforms (such as Intel's) that use
the reverse representation known as little-endian.
What if you obtain an array of bytes and need to
extract data values of different types from it. For example, a
byte array of 19 bytes might contain one char
type, two int
values, one double
value, and one byte
type. In C/C++ you can use memory pointers to reference different
parts of the array and cast a group of bytes there to a particular
type. In Java that type of direct memory referencing is not allowed.
Instead, you can make the array the source of a
stream with the ByteArrayInputStream
class. You then wrap this stream with DataInputStream
and use its selection of methods for reading different data types.
For example, to extract our data from the 19 elements of a byte
array, we could use the following:
Conversely, you can send a stream of data of different
types to a ByteArrayOutputStream
and then extract its internal byte array. It is convenient to wrap
this stream with DataOutputStream,
which provides a selection of methods for different types of such
as writeInt (int),
writeDouble
(double), and writeChars().