Java Programming, Lecture Notes # 1378
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.
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.
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:
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.I will have some more to say about the safe aspects of the array shortly.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."
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.
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.
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.
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.
-end-