Data Structures in Java: Part 15

Baldwin shows you how to use the simpler version of the overloaded toArray method that is declared in the Collection interface.  He also explains why you need to exercise care when using the elements stored in the resulting array to avoid corrupting the state of the objects referred to by the elements in the collection.

The toArray Method, Part 1

Published:  September 17, 2001
By Richard G. Baldwin

Java Programming, Lecture Notes # 1378


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 14, The Comparator Interface, Part 6.

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 first 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 toArray method, which is 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

In earlier lessons, I used the toArray method, declared in the Collection interface, to copy elements from a collection into an array.  However, in those lessons, I didn't take the time to fully explain how to use the method.  Also, I didn't fully explain the precautions that you need to take when you use the method.

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

public Object[] toArray()
public Object[] toArray(Object[] a)

In this lesson, will teach you how to use the first (simpler) version of the toArray method.  I will also show why 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.

I will teach you how to use the second (more complex) version of the toArray method in the next lesson.

Discussion and Sample Program

Beginning with a quiz

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 the program.
 
//File ToArray01.java
//Copyright 2001, R.G.Baldwin
import java.util.*;
import javax.swing.*;

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

class Worker{
  public void doIt(){
    Collection ref;

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

    //Modify a property of an object
    // referred to by one of the
    // elements in the array. Display
    // array contents after 
    // modification
    System.out.println(
            "Modified array contents");
    ((JComponent)array[0]).
                  setToolTipText("XX");
    showArray(array);
    
    //Display the contents of the
    // collection
    System.out.println(
                "Collection contents");
    showCollection(ref);
  }//end doIt()
//-----------------------------------//
    
  //Utility method for displaying
  // array contents
  void showArray(Object[] array){
    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){
    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:

Collection contents
B0 B1 L2 B3 B4 L5
New array contents
B0 B1 L2 B3 B4 L5
Modified array contents
XX B1 L2 B3 B4 L5
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.

A new LinkedList collection

The code in Listing 2 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 after it has been populated.  The list is displayed by passing the LinkedList object's reference to a method named showCollection.
 
    Collection ref;
    ref = new LinkedList();

    Populator.fillIt(ref);

    System.out.println(
                "Collection contents");
    showCollection(ref);

Listing 2

The LinkedList class

The LinkedList class is one of the concrete class implementations of the Collections Framework.  This class implements the Collection interface and the List interface.  Thus, it adheres to the contracts and stipulations of the List interface.

Here is part of what Sun has to say about this class:

"Linked list implementation of the List interface. Implements all optional list operations, and permits all elements (including null). In addition ..."
Populating the LinkedList collection

The beginning of the static fillIt method, used to populate the collection, is shown in Listing 3.
 
  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());

Listing 3

As shown in Listing 3, the fillIt method begins by invoking the add method six times in succession, passing references to new anonymous objects as a parameter to the add method.

Four buttons and two labels

Four of the objects are instantiated from the class named JButton.  Two of the 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()

Why am I using Swing GUI components?

I really don't plan to do anything special with these two Swing GUI components.  Rather, I chose to use them for illustration purposes simply because they possess the characteristics that I need for this lesson, and the next lesson.  Those characteristics are:

Making the objects distinguishable

After the code in Listing 3 has been executed, the buttons and labels are indistinguishable on the basis of the value of their toolTipText property.

The code in Listing 4 deals with this issue.  This code 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.
 
    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

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.

Why populate this way?

This approach to population is, admittedly, a little bit of an overkill for illustrating what I want to illustrate in this program.  However, I plan to use the same fillIt method in the sample program in the next lesson, and it won't be an overkill there.

Display the collection

The code in Listing 2 above invokes the showCollection method to display the contents of the populated LinkedList collection.  The showCollection method is shown in Listing 5
 
  void showCollection(Collection ref){
    Iterator iter = ref.iterator();
    while(iter.hasNext()){
      System.out.print(
             ((JComponent)iter.next()).
               getToolTipText() + " ");
    }//end while loop
    System.out.println();
  }//end showCollection

Listing 5

By now, you should have no difficulty understanding the code in Listing 5.  This code gets an iterator on the incoming reference of type Collection.  The code then uses that iterator to gain access to each element in succession, displaying the String value of the toolTipText property belonging to a particular object during each iteration.

Downcast is required

Note that the next method of the Iterator interface returns a reference to the next element in the collection, as type Object.

In order to invoke the getToolTipText method on the returned reference, the reference must be downcast to type JComponent.  Since both JButton and JLabel extend JComponent, and the getToolTipText method is declared in the JComponent class, it is not necessary to be concerned as to whether an object is type JButton or type JLabel to display the value of the toolTipText property. (This is an example of polymorphic behavior based on class inheritance.)

The output for the collection

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

Collection contents
B0 B1 L2 B3 B4 L5

By examining the "B" and "L" characters in this output, you can identify the JButton objects and the JLabel objects.

Copy collection elements into an array

The code in Listing 6 shows how to use the simple version of the toArray method to create an array of type Object that contains a copy of each element in the LinkedList collection.
 
    Object[] array = ref.toArray();

Listing 6

The toArray method

Here is some of what Sun has to say about this version of the toArray method:

"Returns an array containing all of the elements in this collection. If the 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.

The returned array will be "safe" in that no references to it are maintained by this collection. ... The caller is thus free to modify the returned array."

I will have some more to say about the safe aspects of the array shortly.

Display the array contents

The code in Listing 7 invokes a method named showArray to cause the current contents of the array to be displayed.
 
    System.out.println(
                 "New array contents");
    showArray(array);

Listing 7

The entire showArray method is shown in Listing 8.
 
  void showArray(Object[] array){
    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()

Listing 8

The showArray method

The behavior of the ShowArray method is straightforward.  The method uses a for loop to access each of the elements stored in the array in increasing index order.

A test is made to determine if the element contains a null reference.  If so, then the word null is displayed for that element.  If not, the getToolTipText method is used to access and display the value of the toolTipText property for each element in the array.

The output for the array

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

New array contents
B0 B1 L2 B3 B4 L5

As you can see, (except for the String that identifies the type of output) this is an exact match to the output produced when the contents of the collection were displayed.

How "safe" is the array?

While it is "safe" to modify the contents of the array as explained in the quotation from Sun earlier, there is still some danger here that you need to be aware of.

Java collections do not store objects.  Rather, Java collections store references to objects.  In Java, it is entirely possible to have two or more references to the same object.

Array contains copies of references to objects

Each element in the array is a copy of an element in the collection.

Therefore, at this point, for each object being managed by the collection, at least two references exist that refer to that object.  One copy is contained in the collection.  The other copy is contained in the collection.

If you use a reference stored in the array to modify the state of one of those objects, that modification is made to the object that is also referenced by an element in the collection.  This may or may not be what you intend.  It's not necessarily a problem as long as you understand what is going on and be careful how you use the references stored in the array.

Modifying the state of an object

The code shown in Listing 9 invokes the setToolTipText method on the reference stored in the first element in the array to modify the state of the object to which that reference refers.  Then the code invokes the showArray method to display the contents of the array.
 
    System.out.println(
            "Modified array contents");
    ((JComponent)array[0]).
                  setToolTipText("XX");
    showArray(array);

Listing 9

The toolTipText property value for each of the objects referred to by the remaining elements is left undisturbed.

Display array contents after object modification

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

Modified array contents
XX B1 L2 B3 B4 L5

As you can see, except for the first element, this is a match for the display of the array contents before the state of the object referred by the first element was modified.  However, the toolTipText property for the object referred to by the first element now contains the string "XX", instead of the string "B0" as before.

Now, display the contents of the collection again

The code in Listing 10 displays the state of each of the objects referred to by the elements in the LinkedList collection.
 
    System.out.println(
                "Collection contents");
    showCollection(ref);

Listing 10

The output produced by Listing 10 is shown below:

Collection contents
XX B1 L2 B3 B4 L5

As you can see, the state of the object referred to by the reference stored in the first element of the collection is also changed.  The toolTipText property for that object now contains the string "XX" instead of "B0" as before.

The bottom line

It is safe to modify the contents of the array, even to replace the references in the array with references to other objects.  Such a replacement has no impact on the contents of the collection.

However, it is also possible to use the elements of the array to modify the state of the objects referred to by the elements in the collection.

If this is what you need to do, that's great.  However, if that is not what you need to do, that may be a problem.  So, the bottom line is -- be careful what you do with the elements in the array.

Summary

In this lesson, I taught you how to use the simpler version of the overloaded toArray method, declared in the Collection interface, to copy the elements from a collection into an array of type Object.

I also showed why 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?

In the next lesson, I will teach you how to use the other, more complex version of the overloaded toArray method.


Copyright 2001, 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 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.

baldwin.richard@iname.com

-end-