JavaUnderstanding the Buffer class in Java

Understanding the Buffer class in Java

Preface

#1780

New features in SDK Version 1.4.0

The recently released JavaTM 2 SDK, Standard Edition Version
1.4.0 contains a number of new features.  I plan to publish articles
explaining how to use some of those new features from time to time, and
this is the first such article.

Among the new features is a new I/O API.  Here is how Sun describes
that API and the new features that it provides:

“The new I/O (NIO) APIs introduced in v 1.4 provide new
features and improved performance in the areas of buffer management, scalable
network and file I/O, character-set support, and regular-expression matching.
The NIO APIs supplement the I/O facilities in the java.io package.”

Basic classes

The abstract Buffer class, and its subclasses, are basic
to many of the new features in the NIO.  One of those subclasses is
named ByteBuffer.  Since Buffer is abstract, you can
only work with it in terms of its subclasses.  In this article, I
will use the ByteBuffer class to explore the features of the Buffer
class.

You must understand how to use the Buffer class and its subclasses
before you can understand how to use many of the other classes in the API. 
Therefore, the main purpose of this lesson is to help you understand how
to use the features of the Buffer class.  I will describe many
of those features, and will illustrate the use of those features by explaining
the code in a sample program.

Viewing tip

You may find it useful to open another copy of this lesson in a separate
browser window.  That will make it easier for you to scroll back and
forth among the different listings and figures while you are reading about
them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection
of online Java tutorials.  You will find those lessons published at
Gamelan.com
However, as of the date of this writing, Gamelan doesn’t maintain a consolidated
index of my Java tutorial lessons, and sometimes they are difficult to
locate there.  You will find a consolidated index at
Baldwin’s
Java Programming Tutorials
.

Discussion
and Sample Code


The inheritance model

The class named ByteBuffer extends the abstract class named Buffer
Because Buffer is abstract, it is not possible to create an instance
of Buffer.  Rather, the capabilities of Buffer become
available
when you create an instance of one of the subclasses of Buffer
The Sun documentation lists the following known subclasses of Buffer:

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

As you can see from the names of the subclasses, there is one subclass
of the Buffer class for each non-boolean primitive type.  I
will use the ByteBuffer subclass in this lesson to illustrate the
features inherited from the Buffer class.

A container for primitive data

You may already be aware that none of the container classes in the Java
Collections Framework
are designed to contain primitive data. 
Rather, those containers are all designed to contain references to objects. 
If you want to store primitive data in one of those containers, you must
first wrap the primitive value in an object.

Sun describes Buffer as “A container for data of a specific
primitive type.”
  However, as you will see in a subsequent lesson,
an object of the ByteBuffer class can also be used as a container
for storing a mixture of data of many different primitive types.

Three important properties

Sun tells us ” …the essential properties of a buffer are its capacity,
limit, and position.”

I will illustrate these three properties in the sample program later
in this lesson.  For now, here is a brief description of each of the
three properties of a buffer:

  • capacity:  The number of elements the buffer contains; never
    negative and never changes.
  • limit:  The index of the first element that should not be read
    or written; never negative and never greater than the capacity.
  • position:  The next element to be read or written; never negative
    and never greater than the limit.

put and get operations

Subclasses of Buffer (such as ByteBuffer) use put
and get operations to store data into a buffer and to retrieve data
from the buffer (to transfer data into and out of the buffer). 
Each subclass defines two categories of put and get operations:
relative
and absolute.

Relative put and get operations

Relative data transfer operations store or retrieve one or more
elements starting at the current position.  The position
is automatically incremented based on the number of items transferred and
the type of data transferred.  Transfer requests that exceed the limit
cause exceptions to be thrown with no data being transferred.

Absolute put and get operations

Absolute data transfer operations take an element index as a
parameter and use that index to store or retrieve data.  These operations
do not affect the value of the position property.  Absolute
put
and get operations throw an exception if the index exceeds the limit.

The channel concept

Here is another important quotation from Sun.  I show it here simply
to introduce the concept of a channel, which will be the topic of
a future lesson.

“Data may … be transferred into or out of a buffer by
the I/O operations of an appropriate channel, …”

One of the main reasons for discussing Buffer in this lesson is
to prepare you to understand I/O channels, which I plan to discuss
in a subsequent lesson

Mark and reset

The Buffer class also supports the concept of mark and
reset. 
It is just about impossible to discuss one without the other.  For
example, according to Sun, here is a description of the behavior of the
reset
method:

“Resets this buffer’s position to the previously-marked
position.”

Similarly, here is Sun’s description of a buffer’s mark.

“A buffer’s mark is the index to which its position will
be reset when the reset method is invoked.”

Interaction rules

Here are some rules that apply to the interaction of mark, position,
limit,
and capacity:

  • The mark is not always defined
  • When the mark is defined,
    • The value of the mark is never negative
    • The value of the mark is never greater than the position
    • The mark is discarded when the position or the limit
      is adjusted to a value smaller than the mark
    • 0 <= mark <= position <= limit <= capacity
  • Invoking the method named mark sets the buffer’s mark to
    its current position
  • When the mark is not defined, invoking the reset method causes
    an exception to be thrown

A new buffer always has a position of zero and a mark that
is undefined. The initial limit and capacity of a new buffer
depend on the type of the buffer and its construction.

Setter and getter methods

The Buffer class provides methods for setting and getting
the values of the position, and limit properties, and for
getting
the value of the capacity property.  However, these methods
do not conform to JavaBeans design patterns for properties.  For example,
here are descriptions of the methods for getting and setting the limit
property of a buffer:

  • limit() – Returns this buffer’s limit as type int.
  • limit(int newLimit) – Sets this buffer’s limit and returns type
    Buffer.

As you can see, unlike JavaBeans design patterns, the difference between
setting
and getting in this case is based on overloading the method name. 
This is typical of the setter and getter methods for each
of the three properties listed earlier.

Method chaining

Note that the second method described above returns a reference to the
buffer.  Other methods of the Buffer class also return a reference
to the buffer.  This makes it possible to use method invocation
chaining
syntax such as that shown in Figure 1.

 

buf.rewind().position(2).mark();

Figure 1

I will have more to say about this later.

Other useful methods

The Buffer class defines several other methods that can be used
to operate on a buffer, including the following.  The behaviors of
these methods, (with respect to changing the values of position and
limit),
are very important.

  • reset – Resets this buffer’s position to the previously-marked
    position.
  • clear – Clears the buffer. The position is set to zero, the
    limit
    is set to the capacity, and the mark is discarded.
  • flip – The limit is set to the current position and
    the position is set to zero. The mark is discarded.
  • rewind – Rewinds the buffer. The position is set to zero,
    the mark is discarded, and the limit is unchanged.
  • hasRemaining – Returns boolean to tell whether there are
    any elements between the current position and the limit.
  • remaining – Returns the number of elements between the current position
    and the limit.

I will illustrate most of these methods in the sample program later in
this lesson.

Read-only buffers

It is possible to create buffers that are readable but not writable.

(For example, see the documentation for the asReadOnlyBuffer
method of the ByteBuffer class.)

Methods that normally change the contents of a buffer will throw a ReadOnlyBufferException
when invoked on a read-only buffer.

While a read-only buffer does not allow its content to be changed, its
mark,
position,
and limit values may be changed. You can determine
if a buffer is read-only by invoking its isReadOnly method.

The ByteBuffer class

As mentioned earlier, the ByteBuffer class extends the Buffer
class, and as such, inherits the capabilities discussed above.  In
addition, the ByteBuffer class provides new capabilities that are
not defined in the Buffer class.

I will use the ByteBuffer class in a sample program to illustrate
the features inherited from the Buffer class.  I encourage
you to compile and execute this sample program, and to experiment with
it by making changes while observing the results of your changes.

Reading and writing single bytes

The ByteBuffer class inherits numerous features from the Buffer
class, and adds new features of its own.  I will discuss the new features
added by the ByteBuffer class in a future lesson.  In this
lesson, I will concentrate on the features inherited from the Buffer
class, and will limit the use of ByteBuffer features to those required
to illustrate the inherited features.

The put and get methods

The abstract Buffer class does not provide methods for storing
or retrieving data from a buffer.  Rather, that capability is provided
by ByteBuffer and other subclasses of Buffer.

The ByteBuffer class provides get and put methods
for reading and writing single bytes in both an absolute and a relative
sense.  These features, along with others, are illustrated in the
program named Buffer01, which I will discuss in fragments. 
A complete listing of the program is provided in Listing 17 near the end
of the lesson.

The sample program named Buffer01

The sample program named Buffer01 illustrates most of the methods
of the Buffer class and some of the methods of the ByteBuffer
class.

Listing 1 shows the beginning of the controlling class named Buffer01
Listing 1 also shows the import directive used by this program, to remind
you that this is a new API for input/output.

 

import java.nio.*;

class Buffer01{

Listing 1

The java.nio package did not exist prior to the release of version
1.4.0.  Therefore, in order to compile and execute this sample program,
you will need to have version 1.4.0 or later installed on your system.

Displaying buffer properties

Listing 2 shows the first of three convenience methods designed to make
the code in the main body of the program simpler and easier to understand.

 

  static void showBufferProperties(
                           Buffer buf){
    System.out.println(
       "Buffer Properties: "
                    +"n  capacity=" 
                    + buf.capacity()
                    + " limit=" 
                    + buf.limit()
                    + " position=" 
                    + buf.position());
  }//end showBufferProperties

Listing 2

The purpose of the method named showBufferProperties is to get
and display the
capacity, limit, and position properties
of a Buffer object whose reference is received as an incoming parameter.

(The actual type of the objects passed to this method in
this program is ByteBuffer.  However, because ByteBuffer
extends Buffer, and all the methods invoked by the code in this
method are defined in Buffer, the type of the incoming object can
be Buffer or any subclass of Buffer.)

The boldface code in Listing 2 identifies the getter methods used
to get the values of the three properties listed above.  The remaining
code in Listing 2 is a large print statement that causes the values returned
by the getter methods to be displayed on the standard output device. 
A sample of the screen output produced by this method is shown in Figure
2.

 

Buffer Properties:

  capacity=8 limit=8 position=0

Figure 2

Display buffer data

The method shown in Listing 3 gets and displays the data stored in the
buffer beginning with the element at the current value of the position
property and extending to the value of the limit property.

 

  static void showBufferData(
                       ByteBuffer buf){
    System.out.println(
                   "Show buffer data");
    while(buf.hasRemaining())
      System.out.print(
                      buf.get() + " ");
    System.out.println();//blank line
  }//end showBufferData

Listing 3

This is accomplished using the relative get method defined in
the ByteBuffer class.

Parameter is not type Buffer

Note that the incoming parameter to this method is type ByteBuffer
and is not type Buffer, as was the case in Listing 2.  This
is because the get method invoked by the code in this method is
not defined in the Buffer class.  Rather, it is defined in
the ByteBuffer class, and therefore can only be invoked on a reference
of type ByteBuffer, or a subclass of the ByteBuffer class.

The hasRemaining method

The code in Listing 3 invokes two interesting methods.  The first
is the hasRemaining method.  This method is much like the methods
of the Iterator and Enumeration interfaces, used to iterate
on objects instantiated from the concrete classes of the Java Collections
Framework.

The hasRemaining method is defined in the Buffer class,
and tells whether there are any elements remaining between the current
position
and the limit.  This method returns a boolean, which
is true only if there is at least one element remaining in the buffer. 
Thus, it works very nicely in the conditional clause of a while
loop for the purpose of iterating on a buffer.

The relative get method

The second method of interest in Listing 3 is the relative
get
method of the ByteBuffer class.  This method reads and returns
the byte at the buffer’s current position, and then increments the
position.  Thus, it also works quite well in an iterator loop for
a buffer (provided you have exercised proper control over the values
of the position and limit properties beforehand).

Display array data

The third convenience method, shown in Listing 4, is a method designed
simply to display the data in an array object of type byte.

 

  static void showArrayData(
                         byte[] array){
    System.out.println(
                    "Show array data");
    for(int cnt = 0; 
            cnt < array.length; cnt++){
      System.out.print(
                     array[cnt] + " ");
    }//end for loop
    System.out.println();//blank line
  }//end showArrayData

Listing 4

I am assuming that you are already familiar with the use of array objects
in Java, and therefore, I won’t discuss this code in detail.  If that
is not the case, you can learn about array objects at Baldwin’s
Java Programming Tutorials
.

The main method creates an array object

There are several ways to create and populate a buffer in Java. 
One of those ways is to wrap an existing array object in a buffer. 
To do that, you need an existing array object.  (I will discuss
the other ways to create a buffer in a future lesson.)

Listing 5 shows the beginning of the main method.  The code
in Listing 5 creates, populates, and displays an eight-element array object
containing data of type byte.

 

  public static void main(
                        String[] args){
    System.out.println(
      "Create, populate, and display "
       + "nan 8-element byte array");
    byte[] array = {0,1,2,3,4,5,6,7};
    showArrayData(array);

Listing 5

Again, I am assuming that you are already familiar with the use of array
objects in Java, and therefore, I won’t discuss this code in detail. 
The code in Listing 5 produces the output shown in Figure 3.

 

Create, populate, and display

an 8-element byte array

Show array data

0 1 2 3 4 5 6 7

Figure 3

I show this here because we will want to compare it with the data stored
in our buffer object later.

Create the buffer

As mentioned above, there are several ways to create a buffer, and one
of them is shown in Listing 6.

 

    System.out.println(
                 "Wrap the byte array "
                      + "in a buffer");
    ByteBuffer buf = 
                ByteBuffer.wrap(array);

Listing 6

Listing 6 invokes the static wrap method of the ByteBuffer
class to create a buffer that wraps an existing array object.

What is the significance of wrapping an array
object?

There are two overloaded versions of the wrap method, one that
requires incoming offset and length parameters, and one that
does not.  (Both versions require an incoming reference to an array
object.)
  I used the simpler of the two versions, which does not
require
offset and length.

For both versions, the new buffer is backed up by, or connected to,
the byte array, which it wraps.  Modifications to the buffer cause
the array contents to be modified.  Modifications to the array cause
the buffer contents to be modified.  (It appears as though they
are really the same set of data.)

For the version of the wrap method that I used, the capacity
and limit of the new buffer is the same as array.length. 
The initial value of the position property of the new buffer is
zero, and its mark is undefined.

For the more complex version, the initial values of the buffer properties
are determined by the values of the offset and length parameters
passed to the wrap method.

Show buffer properties and data

The code in Listing 7 displays the properties of the new buffer. 
Then it uses the relative get method to display the contents of
the buffer.  After that, it displays the properties again.

 

    showBufferProperties(buf);
    showBufferData(buf);
    showBufferProperties(buf);

Listing 7

The output produced by the code in Listing 7 is shown in Figure 4.

 

Buffer Properties:

 capacity=8 limit=8 position=0

Show buffer data

0 1 2 3 4 5 6 7

Buffer Properties:

 capacity=8 limit=8 position=8

Figure 4

There are several important things to note about this output:

  • The initial values of the buffer properties match that described above
    for the simpler version of the Wrap method.
  • The contents of the buffer match the contents of the array object displayed
    in Figure 3.
  • The value of the position property changes from 0 to 8 when the
    relative get method is used in an iterative loop to display each
    element in the buffer.

Modifications to the buffer …

I stated earlier, “Modifications to the buffer cause the array contents
to be modified, and modifications to the array cause the buffer contents
to be modified.”

This is illustrated in the next several fragments.

 

    System.out.println(
         "Modify first array element");
    array[0] = 10;
    showArrayData(array);

Listing 8

The code in Listing 8 changes the value in the first array element from
0 to 10, and then displays the modified contents of the array object. 
We will see that this causes the value of the first element in the buffer
to change accordingly.

Flip the buffer

Before we can use the showBufferData method to display the contents
of the buffer, we must do something about the position property
whose value is currently 8.  There are several ways to do this, but
I took this opportunity to illustrate the use of the flip method
of the Buffer class.  The use of the flip method is
shown in Listing 9.

 

    System.out.println(
        "Flip the buffer");
    buf.flip();

Listing 9

According to Sun, the flip method “makes a buffer ready for
a new sequence of … relative get operations.  It sets the limit
to the current position and then sets the position to zero.”

That is exactly what I needed to do in this case, so the flip
method worked quite nicely.

Display buffer properties and data

Listing 10 displays the new property values for the buffer, and then
displays the contents of the buffer.

 

    showBufferProperties(buf);
    showBufferData(buf);

Listing 10

The output produced by Listings 8, 9, and 10 is shown in Figure 5.

 

Modify first array element

Show array data

10 1 2 3 4 5 6 7

Flip the buffer

Buffer Properties:

 capacity=8 limit=8 position=0

Show buffer data

10 1 2 3 4 5 6 7

Figure 5

The important things to note in Figure 5 are:

  • Invocation of the flip method caused the position property
    value to be set to zero.
  • The value in the first element of the buffer was changed when the value
    in the first element of the wrapped array was changed.

Rewind the buffer

A little later, I will illustrate that changing the contents of the
buffer causes the corresponding contents of the wrapped array to change
accordingly.  First, however, I need to illustrate the rewind
operation on the buffer.  This is accomplished in Listing 11.

 

    System.out.println(
                  "Rewind the buffer");
    buf.rewind();
    showBufferProperties(buf);
    showBufferData(buf);

Listing 11

The code in Listing 11 invokes the rewind method on the buffer
and then displays the properties and contents of the buffer.

The rewind method is a method of the Buffer class. 
According to Sun, the rewind method “makes a buffer ready for
re-reading the data that it already contains: It leaves the limit unchanged
and sets the position to zero.”
  You might equate this to rewinding
a VCR tape in order to play it again.

And the output is …

The code in Listing 11 produces the output shown in Figure 6.

 

Rewind the buffer

Buffer Properties:

 capacity=8 limit=8 position=0

Show buffer data

10 1 2 3 4 5 6 7

Figure 6

There are no surprises here.  By now, you probably knew what to
expect as output from this operation.

The absolute put method

As I explained earlier, the ByteBuffer class provides both absolute
and relative versions of the put and get methods. 
So far, we have seen the use of the relative version of the get
method only.  The boldface code in Listing 12 uses the absolute
version of the put method to modify the contents of the buffer at
index 3.  In particular, the value stored at index 3 in the buffer
is overwritten by the value 20.

 

    System.out.println(
            "Modify the buffer using");
    System.out.println(
                "absolute put method");
    buf.put(3,(byte)20);
    buf.rewind();
    showBufferData(buf);
    showArrayData(array);

Listing 12

After the value is modified, the buffer is rewound.  Then the data
in the buffer and the data in the array are displayed for comparison. 
The output produced by Listing 12 is shown in Figure 7.

 

Modify the buffer using

absolute put method

Show buffer data

10 1 2 20 4 5 6 7

Show array data

10 1 2 20 4 5 6 7

Figure 7

Perhaps the most important things to observe in this output are:

  • The value of the element at index 3 in the buffer is changed to 20.
  • The value of the element at index 3 in the array is also changed to 20.

Chaining and marking

As explained earlier, several of the methods of the Buffer class
return a reference to the buffer.  This makes it possible to chain
method invocations as shown by the boldface code in Listing 13.

 

    System.out.println(
     "Mark at index 2 using chaining");

    buf.rewind().position(2).mark();

Listing 13

The boldface statement in Listing 13 is executed from left to right. 
The behavior of the statement accomplishes the following operations in
order:

  • Rewind the buffer
  • Set the value of the position property to 2.
  • Set the mark to the current value of the position property
    (2).

Now change the position property value

The code in Listing 14 changes the value of the position property
from 2 to 4.  (It is important to note that this does not change
the mark.)


 

    System.out.println(
                  "Set position to 4");
    buf.position(4);
    showBufferData(buf);

Listing 14

Having changed the value of the position property, Listing 14
invokes the showBufferData method to display the contents of the
buffer.  The screen output is shown in Figure 8.

 

Mark at index 2 using chaining

Set position to 4

Show buffer data

4 5 6 7

Figure 8

Recall that the showBufferData method displays the data from
the current
position to the limit.  Therefore, in this
case, the display does not begin with the element at index zero. 
Rather, it begins with the element at index 4, which is the current value
of the position property.

Reset to a previous mark

Listing 15 invokes the reset method on the buffer, and then displays
its contents again.

 

    System.out.println(
             "Reset to previous mark");
    buf.reset();
    showBufferData(buf);

Listing 15

The reset method is a method of the buffer class. 
According to Sun, invocation of the reset method “Resets this
buffer’s position to the previously-marked position.”

Recall that the previously marked position was the element at index
value 2.  Thus, when the showBufferData method is used to display
the contents of the buffer, the screen output is as shown in Figure 9.

 

Reset to previous mark

Show buffer data

2 20 4 5 6 7

Figure 9

The output shows that the value of the position property is set
to element index 2 when the reset method is invoked.  Then
the showBufferData method displays the contents of the buffer from
index 2 to the limit.

Thus, the ability to mark and reset makes it possible
for your program to remember a position and return to that position
later.  You need to exercise caution, however, because several of
the operations that you can perform on a buffer cause the mark to
be discarded.  If you invoke reset on a buffer for which the
mark
has been discarded, an exception will be thrown.

Is this a read-only buffer?

Although it is possible to create read-only buffers, the output produced
by the code in Listing 16 shows that this is not a read-only buffer.

 

    System.out.println(
                "Buffer is read only: "
                   + buf.isReadOnly());
Listing 16

Listing 16 produces the output shown in Figure 10.

 

Buffer is read only: false

Figure 10

So there you have it

By now you should understand a lot about the new Buffer class
in the new java.nio package.

Future articles will discuss ByteBuffer, Channels, and
other new I/O features introduced in Java version 1.4.0.

Run the Program


If you haven’t already done so, I encourage you to copy the code from Listing
17 into your text editor, compile it, and execute it.  Experiment
with it, making changes, and observing the results of your changes.

Remember, however, that you must be running version 1.4.0 or later to
compile and execute this program.

Complete Program Listing


A complete listing of the program is shown in Listing 17 below.

 

/* File Buffer01.java
Copyright 2002, R.G.Baldwin

Illustrates most methods of Buffer 
class and some methods of ByteBuffer
class.

Tested using JDK 1.4.0 under Win2000

Output is:

Create, populate, and display
an 8-element byte array
Show array data
0 1 2 3 4 5 6 7

Wrap the byte array in a buffer
Buffer Properties:
  capacity=8 limit=8 position=0
Show buffer data
0 1 2 3 4 5 6 7
Buffer Properties:
  capacity=8 limit=8 position=8

Modify first array element
Show array data
10 1 2 3 4 5 6 7
Flip the buffer
Buffer Properties:
  capacity=8 limit=8 position=0
Show buffer data
10 1 2 3 4 5 6 7

Rewind the buffer
Buffer Properties:
  capacity=8 limit=8 position=0
Show buffer data
10 1 2 3 4 5 6 7

Modify the buffer using
absolute put method
Show buffer data
10 1 2 20 4 5 6 7
Show array data
10 1 2 20 4 5 6 7

Mark at index 2 using chaining
Set position to 4
Show buffer data
4 5 6 7
Reset to previous mark
Show buffer data
2 20 4 5 6 7

Buffer is read only: false
**************************************/

import java.nio.*;

class Buffer01{
  static void showBufferProperties(
                           Buffer buf){
    System.out.println(
       "Buffer Properties: "
                    +"n  capacity=" 
                    + buf.capacity()
                    + " limit=" 
                    + buf.limit()
                    + " position=" 
                    + buf.position());
  }//end showBufferProperties
  //---------------------------------//
  
  static void showBufferData(
                       ByteBuffer buf){
    //Displays buffer contents from 
    // current position to limit using
    // relative get method.
    System.out.println(
                   "Show buffer data");
    while(buf.hasRemaining())
      System.out.print(
                      buf.get() + " ");
    System.out.println();//blank line
  }//end showBufferData
  //---------------------------------//

  static void showArrayData(
                         byte[] array){
    System.out.println(
                    "Show array data");
    for(int cnt = 0; 
            cnt < array.length; cnt++){
      System.out.print(
                     array[cnt] + " ");
    }//end for loop
    System.out.println();//blank line
  }//end showArrayData
  //---------------------------------//
  
  public static void main(
                        String[] args){
    
    //Wrap a byte array into a buffer
    System.out.println(
      "Create, populate, and display "
       + "nan 8-element byte array");
    byte[] array = {0,1,2,3,4,5,6,7};
    showArrayData(array);
    System.out.println();//blank line
    
    System.out.println(
                 "Wrap the byte array "
                      + "in a buffer");
    ByteBuffer buf = 
                ByteBuffer.wrap(array);
    showBufferProperties(buf);
    showBufferData(buf);
    showBufferProperties(buf);
    System.out.println();//blank line
        
    //Mods to the buffer will cause the
    // array to be modified and vice 
    // versa.
    System.out.println(
         "Modify first array element");
    array[0] = 10;
    showArrayData(array);

    System.out.println(
                    "Flip the buffer");
    buf.flip();
    showBufferProperties(buf);
    showBufferData(buf);
    System.out.println();//blank line
    
    System.out.println(
                  "Rewind the buffer");
    buf.rewind();
    showBufferProperties(buf);
    showBufferData(buf);
    System.out.println();//blank line

    System.out.println(
            "Modify the buffer using");
    System.out.println(
                "absolute put method");
    buf.put(3,(byte)20);
    buf.rewind();
    showBufferData(buf);
    showArrayData(array);
    System.out.println();//blank line
    
    //Illustrate chaining, marking, 
    // and reset
    System.out.println(
     "Mark at index 2 using chaining");
    buf.rewind().position(2).mark();
    System.out.println(
                  "Set position to 4");
    buf.position(4);
    showBufferData(buf);
    System.out.println(
             "Reset to previous mark");
    buf.reset();
    showBufferData(buf);
    System.out.println();//blank line
    
    System.out.println(
                "Buffer is read only: "
                   + buf.isReadOnly());
  }// end main

}//end class Buffer01 definition

Listing 17

Copyright 2002, Richard G. Baldwin.  Reproduction in whole or in
part in any form or medium without express written permission from Richard
Baldwin is prohibited.

About the author

Richard Baldwin
is a college professor (at Austin Community College in Austin, TX) and
private consultant whose primary focus is a combination of Java, C#, and
XML. In addition to the many platform and/or language independent benefits
of Java and C# applications, he believes that a combination of Java, C#,
and XML will become the primary driving force in the delivery of structured
information on the Web.

Richard has participated in numerous consulting projects, and he
frequently provides onsite training at the high-tech companies located
in and around Austin, Texas.  He is the author of Baldwin’s Programming
Tutorials,
which has gained a worldwide following among experienced and aspiring programmers.
He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology
to real-world problems.

# # #

Latest Posts

Related Stories