Java Data & Java Data Structures in Java: Part 16, The toArray Method, Part 2

Data Structures in Java: Part 16, The toArray Method, Part 2

Java Programming, Lecture Notes #1380


Preface


A miniseries

This lesson is part of a miniseries on Java data structures and the
Java Collections Framework.  The first lesson in the miniseries
was entitled
Data
Structures in Java: Part 1, Getting Started
.  The previous lesson
was entitled Data
Structures in Java: Part 15, The toArray Method, Part 1
.

The purpose of this miniseries is to help you learn the essential features
of Object-Oriented data structures in Java using the Collections Framework.

A sub-series

This is also the second (and last) lesson in a sub-series on
the toArray method.  The primary purpose of the lessons in
this sub-series is to teach you how to use the overloaded versions of the
toArray
method, which are declared in the Collection interface.

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 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
.

Preview


The Collection interface declares the following
two overloaded versions of the toArray method:

public Object[] toArray()

public Object[] toArray(Object[] a)

In the previous lesson, I taught you how to use
the first (simpler) of the two methods.  I also discussed the
need to exercise care when using the elements stored in the returned array
to avoid corrupting the state of the objects referred to by elements in
the collection.

In this lesson, I will teach you how to use the
second (more-complex) version of the toArray method declared
in the Collection interface.  I will discuss issues regarding
the type of the array and the types of the objects referred to by the elements
in the collection.  I will also discuss issues regarding the relative
sizes of the array and the collection.

Finally, I will reaffirm that you need to exercise
care when using the elements stored in the array, to avoid corrupting the
state of the objects referred to by the elements in the collection.

Discussion
and Sample Program


Beginning with a quiz

As has been the case in the last few lessons, let’s begin with a little
quiz to test your prior knowledge of the Collections Framework.  To
take this quiz, examine the program shown in Listing 1 and write down the
output produced by that program.

 

//File ToArray02.java
//Copyright 2001, R.G.Baldwin
import java.util.*;
import javax.swing.*;

public class ToArray02{
  public static void main(
                        String args[]){
    new Worker().doIt();
  }//end main()
}//end class ToArray02
//===================================//

class Worker{
  public void doIt(){
    Collection ref;
    
    //Create, populate, and display
    // the contents of an array
    JComponent[] array = 
                     new JComponent[8];
    for(int cnt=0;cnt<8;cnt++){
      array[cnt] = new JButton();
      array[cnt].setToolTipText(
                        "" + (cnt+10));
    }//end for loop
    System.out.println();
    showArray(array,
            "Original array contents");


    //Create, populate, and display the
    // contents of a collection
    ref = new LinkedList();
    Populator.fillIt(ref);
    showCollection(ref,
                "Collection contents");
    
    //Get collection contents into the
    // array and display the new
    // contents of the array.
    array = (JComponent[])ref.
                        toArray(array);
    showArray(array,
                 "New array contents");

    //Modify a property of an object
    // referred to by one of the
    // elements in the array. Display
    // array contents after 
    // modification
    ((JComponent)array[0]).
                  setToolTipText("XX");
    showArray(array,
            "Modified array contents");
    
    //Display the contents of the
    // collection
    showCollection(ref,
                "Collection contents");
  }//end doIt()
//-----------------------------------//
    
  //Utility method for displaying
  // array contents
  void showArray(Object[] array,
                         String title){
    System.out.println(title);
    for(int i = 0; i < array.length;
                                  i++){
      if(array[i] == null){
        System.out.print("null ");
      }else{
        System.out.print(
                ((JComponent)array[i]).
               getToolTipText() + " ");
      }//end else
    }//end for loop
    System.out.println();
  }//end showArray()
//-----------------------------------//

  //Utility method for displaying
  // collection contents
  void showCollection(Collection ref,
                         String title){
    System.out.println(title);
    Iterator iter = ref.iterator();
    while(iter.hasNext()){
      System.out.print(
             ((JComponent)iter.next()).
               getToolTipText() + " ");
    }//end while loop
    System.out.println();
  }//end showCollection
}// end class Worker
//===================================//

class Populator{
  public static void fillIt(
                       Collection ref){
    ref.add(new JButton());
    ref.add(new JButton());
    ref.add(new JLabel());
    ref.add(new JButton());
    ref.add(new JButton());
    ref.add(new JLabel());
    
    Iterator iter = ref.iterator();
    int cnt = 0;
    JComponent refVar;
    while(iter.hasNext()){
      refVar = (JComponent)iter.next();
      if(refVar instanceof JButton){
        refVar.setToolTipText(
                            "B"+cnt++);
      }else{
        refVar.setToolTipText(
                          "L" + cnt++);
      }//end else
    }//end while loop
    
  }//end fillIt()
}//end class Populator

Listing 1

And the answer is …

The correct answer to the quiz is the program output shown below:

Original array contents

10 11 12 13 14 15 16 17

Collection contents

B0 B1 L2 B3 B4 L5

New array contents

B0 B1 L2 B3 B4 L5 null 17

Modified array contents

XX B1 L2 B3 B4 L5 null 17

Collection contents

XX B1 L2 B3 B4 L5

If that was your answer, you probably already understand most of the
material covered in this lesson.  In that case, you might consider
skipping this lesson and moving on to the next lesson.  If that wasn’t
your answer, you should probably continue with your study of this lesson.

Similar to previous program

Except for the use of a different version of the toArray method,
the overall structure of the program in Listing 1 is similar to the program
in the previous lesson.  Therefore, I will concentrate on those aspects
of this program that differentiate it from the program in the previous
lesson.

A populated array

Unlike the program in the previous lesson, the code in Listing 2 creates
and populates an eight-element array of type JComponent.  This
is the array that will be re-populated by the toArray method later
in the program.  The array is populated with a set of initial element
values at this point to make it obvious when it is re-populated (overwritten
elements)
by the toArray method later.

 

    JComponent[] array = 
                     new JComponent[8];

    for(int cnt=0;cnt<8;cnt++){
      array[cnt] = new JButton();
      array[cnt].setToolTipText(
                        "" + (cnt+10));
    }//end for loop
    System.out.println();
    showArray(array,
            "Original array contents");

Listing 2

The JButton class, the JLabel class, and the setToolTipText
method were discussed in detail in the previous lesson, so I won’t repeat
that discussion here.

Display the array contents

After the array is populated by the code in Listing 2, a reference to
the array object is passed to the showArray method (also in Listing
2)
to display the contents of the array.

With the exception of some minor changes implemented in this program
to make the use of the showArray method more compact, this is the
same showArray method used in the previous lesson.  Therefore,
I won’t discuss that method further in this lesson.  The output produced
by the code in Listing 2 is as follows:

Original array contents

10 11 12 13 14 15 16 17

As you can see, each of the eight elements in the array was initialized
with an easily-recognizable and unique value, (which may be overwritten
by the toArray method later).

A new LinkedList collection

The code in Listing 3 creates and populates a new LinkedList
collection.  The collection is populated by passing the LinkedList
object’s reference to a method named fillIt.

The code in Listing 2 also displays the contents of the LinkedList
collection after it has been populated.  The list is displayed by
passing the
LinkedList object’s reference to a method named showCollection.

 

    ref = new LinkedList();
    Populator.fillIt(ref);
    showCollection(ref,
                "Collection contents");

Listing 3

Except for a couple of minor changes to the showCollection method,
the code to create, populate, and display the collection is the same as
the code in the previous lesson.

Populating the LinkedList collection

A couple of points regarding the fillIt method (shown in Listing
4)
are worthy of note.

 

  public static void fillIt(
                       Collection ref){
    ref.add(new JButton());
    ref.add(new JButton());
    ref.add(new JLabel());
    ref.add(new JButton());
    ref.add(new JButton());
    ref.add(new JLabel());
    
    Iterator iter = ref.iterator();
    int cnt = 0;
    JComponent refVar;
    while(iter.hasNext()){
      refVar = (JComponent)iter.next();
      if(refVar instanceof JButton){
        refVar.setToolTipText(
                            "B"+cnt++);
      }else{
        refVar.setToolTipText(
                          "L" + cnt++);
      }//end else
    }//end while loop
    
  }//end fillIt()

Listing 4

The fillIt method begins by invoking the
add method six
times in succession, passing references to new anonymous objects (of
types JButton and JLabel)
as a parameter to the add method.

Four buttons and two labels

Four of the objects are instantiated from the class named JButton
The other two objects are instantiated from the class named JLabel.

Both JButton and JLabel belong to the javax.swing
package.  Further, both are subclasses of the class named JComponent.

The toolTipText property

Finally, both classes have a property named toolTipText, which
can be set and accessed by invoking the following methods on a reference
to the object:

void setToolTipText(String text)

String getToolTipText()

JButton and JLabel

I chose to use objects of these two classes for illustration purposes
simply because they possess the characteristics that I need for this lesson. 
Those characteristics are:

  • Both classes subclass the class named JComponent (a common superclass
    below the Object class).
  • Both classes inherit a property (toolTipText) that can be used to
    identify them later.

Making the objects distinguishable

After adding the objects’ references to the collection, the code in
Listing 4 uses the
setToolTipText method to store a unique String
value
in the
toolTipText property of the object referred to by each of
the elements in the collection.

Identifying the buttons and labels

In addition to storing a unique value in the toolTipText property
of the object referred to by each element, the code in Listing 4 also makes
it possible to distinguish between the JButton objects and the JLabel
objects.  This is accomplished by including an upper-case “B” in the
property value for each JButton, and including an upper-case “L”
in the property value for each JLabel button.

Display the collection

The code in Listing 3 above invokes the showCollection method
to display the contents of the populated LinkedList collection. 
The output produced by the code in Listing 3 is shown below:

Collection contents

B0 B1 L2 B3 B4 L5

Each term in the output is the String value of the toolTipText
property for a particular object.  Hence, there are six terms in the
output, one for each element in the collection.

Copy collection elements into an array

We have now reached the point that is the main thrust of this lesson.

The code in Listing 5 shows how to use the more-complex version of the
toArray
method to copy the elements in the collection into an array.

 

    array = (JComponent[])ref.
                        toArray(array);
    showArray(array,
                 "New array contents");

Listing 5

The code in Listing 5 also causes the contents of the array to be displayed
after it receives the elements from the collection.

The first statement in Listing 5 causes the first seven elements in
the array to be overwritten with element values from the collection (plus
one null value).

The second statement in Listing 5 causes the contents of the array to
be displayed.

The toArray method

The most important thing to note about Listing 5 is that a reference
to an array object is passed as a parameter to the toArray method.
(The simpler version of the toArray method, discussed in the previous
lesson, doesn’t take any parameters.)

The essential difference

The essential difference between the two overloaded versions of the
toArray
method has to do with the origin of the array into which the toArray
method copies the elements from the collection.

With the simpler version of the toArray method that takes no
parameters, the toArray method creates a new array object of type
Object,
populates it, and returns that object’s reference as type
Object.

Type is not an issue for the simpler version

Since the new array object is of type Object, there are no issues
regarding type compatibility between the type of the array and the types
of the elements stored in the collection.  A reference to an object
of any type can be stored in an array of the generic type Object[].

Size is not an issue for the simpler version

Also, since the array is created when it is needed by the simpler version
of the toArray method, there are also no size issues.  The
array is created to be of exactly the correct size to contain copies of
all of the elements in the collection.

More-complex version presents some issues

With the more-complex version of the toArray method (shown
in Listing 5)
, the programmer must provide the array object that will
be populated by the toArray method.  In this situation, there
are size issues as well as type issues to be dealt with.

The type issue

Here is some of what the Sun documentation for the LinkedList
class has to say about the type issue for this version of the toArray
method:

“Returns an array containing all of the elements in this
list in the correct order. The runtime type of the returned array is that
of the specified array. …  Throws:  ArrayStoreException – if
the runtime type of (the specified array) is not a supertype of the runtime
type of every element in this list.

In other words, the type of the array passed as a parameter to the toArray
method must be a superclass of the classes from which all of the objects
being managed by the collection were instantiated.

Two types of objects in this collection

In this program, the collection is managing objects of the types JButton
and JLabel.  Each of these types is a subclass of the class
named JComponent.  For that reason, the type of array that
I instantiated and passed to the toArray method is JComponent[].

The size issue

Here is some of what the Sun documentation for the LinkedList
class has to say about the size issue for this version of the toArray
method.

“If the list fits in the specified array, it is returned
therein. Otherwise, a new array is allocated with the runtime type of the
specified array and the size of this list.

If the list fits in the specified array with room to spare (i.e.,
the array has more elements than the list), the element in the array immediately
following the end of the collection is set to null. This is useful in determining
the length of the list only if the caller knows that the list does not
contain any null elements.”

So, what did I do?

Knowing all of this in advance, I purposely caused the size of the JComponent
array to be larger (by two elements) than the number of elements
in the collection.  Therefore, the array that I passed to the toArray
method was populated and a reference to that populated array was returned.

(Had my array been smaller than the number of elements in the collection,
the toArray method would have created and populated a new array of type
JComponent and would have returned a reference to that new array object. 
In that case, my array would have been used by the toArray method only
for the purpose of determining the runtime type of my array.)”

More information from Sun

Here is some additional information about the toArray method
provided by the Sun documentation for the Collection interface:

“If this collection makes any guarantees as to what order
its elements are returned by its iterator, this method must return the
elements in the same order.”

Because the iterator for a LinkedList object returns the elements
in increasing index order, the toArray method, in this case, copies
the element at each index position in the collection into the element at
the same index position in the array.  Thus, reference values are
copied from each element in the collection into the first six elements
in the array.

The output

The output produced by the code in Listing 5 is shown below:

New array contents

B0 B1 L2 B3 B4 L5 null 17

You will note that the first six elements in the array match the six
elements in the collection (the initial values placed in the array earlier
when the array was instantiated have been overwritten).

You will also note that the value of the seventh element in the array
(index
value 6)
has been overwritten with a null reference.

Demonstrates same array was used

Note finally that the last element in the array was not overwritten. 
It still contains the value placed there when the array object was instantiated. 
This demonstrates that the array that I passed to the toArray method
was populated with the collection data, and a reference to that array was
returned by the toArray method.

What if the array was too small?

Had my array been too small, it would have been discarded by the toArray
method.  The toArray method would have created and populated
a new array object of the correct size and runtime type, and would have
returned a reference to that new array.

Not difficult to demonstrate

Although this is not demonstrated by this program, it is easy to modify
the program to demonstrate this feature.

A String representation of the array object can be displayed
using a System.out.println(array) statement before and after the
array is passed to the toArray method.

Array as large as or larger than collection

For the cases where my array contained six, seven, or eight elements,
and the collection contained six elements, the String representations
of the array object before and after the invocation of the toArray
method were the same.  For one case, those String representations
were as follows:

[Ljavax.swing.JComponent;@49ba38

[Ljavax.swing.JComponent;@49ba38

In other words, the reference variable named array referred to
the same array object before and after the invocation of the toArray
method.

Array smaller than the collection

When I reduced the size of the array to five elements, keeping the size
of the collection at six elements, the before and after String representations
of the array object were as follows:

[Ljavax.swing.JComponent;@506411

[Ljavax.swing.JComponent;@21807c

In this case, the reference to the array object returned by the toArray
method was different from the reference that was passed to the toArray
method.  In other words, the returned reference referred to a different
array object than was referred to by the reference that was passed to the
toArray
method.

Modify an object

The code shown in Listing 6 modifies the value of the toolTipText
property of the object whose reference is stored in index 0 of the array.

 

    ((JComponent)array[0]).
                  setToolTipText("XX");
    showArray(array,
            "Modified array contents");
    
    showCollection(ref,
                "Collection contents");


Listing 6

The code in Listing 6 also displays the contents of the array and the
contents of the collection after the modification is made.

The output produced by the code in Listing 6 is shown below:

Modified array contents

XX B1 L2 B3 B4 L5 null 17

Collection contents

XX B1 L2 B3 B4 L5

Now for the caution

Note that the value of the toolTipText property of the object
referred to by the reference at index 0 of the array, and the same property
of the object referred to by the reference at index 0 of the collection
was overwritten by “XX”.  (This is true because both references
refer to the same object.)

This is the case regardless of which version of the toArray method
is used.  Therefore, the same cautions discussed in the previous lesson
apply here as well.

Summary


In this lesson, I taught you how to use the more-complex
version of the two overloaded versions of the toArray method, declared
in the
Collection interface, to copy the elements from a collection
into an array of type
JComponent.

I discussed issues regarding the type of the array
and the type of the objects referred to by the elements in the container. 
I also discussed issues regarding the size of the array as compared to
the number of elements in the collection.

Finally, I reaffirmed that you need to exercise
care when using the elements stored in the array, to avoid corrupting the
state of the objects referred to by the elements in the collection.

What’s Next?


The next several lessons will teach you how to use the Map and SortedMap
interfaces,
and the concrete class implementations of those interfaces.

About the author

Richard Baldwin
is a college professor and private consultant whose primary focus is a
combination of Java and XML. In addition to the many platform-independent
benefits of Java applications, he believes that a combination of Java and
XML will become the primary driving force in the delivery of structured
information on the Web.

Richard has participated in numerous consulting projects involving
Java, XML, or a combination of the two.  He frequently provides onsite
Java and/or XML training at the high-tech companies located in and around
Austin, Texas.  He is the author of Baldwin’s Java Programming Tutorials,
which has gained a worldwide following among experienced and aspiring Java
programmers. He has also published articles on Java Programming in Java
Pro 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.

[email protected]

Latest Posts

Related Stories