The java.util package also provides a Stack class, but according to several books on the subject, it doesn't behave the way we normally expect a stack to behave (I haven't tested it myself). In particular, the Stack class apparently extends the Vector class which makes it possible to instantiate an object of the Stack class, and then access methods of the Vector class that violate the LIFO behavior that we normally expect from a stack.
If I have the time later, I will prepare a lesson on creating a stack using the Vector class that doesn't have this shortcoming.
Therefore, any class can be designed to implement the Enumeration interface. |
What do we mean when we say that we are going to enumerate an object? We mean that we will provide a pair of methods by which a using program can:
A class that implements the Enumeration interface must provide
a definition for the following two methods that are declared in the interface.
public boolean hasMoreElements() public Object nextElement() |
For example, if an object of a linked-list class has the ability to provide an enumeration object on itself, code within the scope of the linked list object can obtain that enumeration object and use it to interate through all the nodes in the linked list.
The methods of the Enumeration interface can be invoked on the enumeration object to provide that code with a sequence of references to the nodes in the list. Then depending on access control considerations, the code can access the individual nodes in that specific linked-list object to do something useful.
It is important to note that an enumeration object is not really an object of the Enumeration class, because there is no such class. Rather, Enumeration is an interface and it is not possible to instantiate objects of an interface type.
However, if an object is instantiated from a class that implements the Enumeration interface, then insofar as the two methods declared in the Enumeration interface are concerned, the object can be treated as if it were of type Enumeration.
Unless the class from which the enumeration object is instantiated contains members that are not declared in the Enumeration interface, you really don't need to care about the actual class from which it was instantiated. You can always refer to it as type Enumeration.
It is also important to note that an enumeration object normally won't contain any hard data. Rather, it will normally contain a reference to the specific object that it was instantiated to enumerate, and such other data as may be necessary for it to reliably execute its two methods. Note however, that an enumeration object designed to enumerate an object which is a complex data structure may require very complex methods to accomplish its task..
When the nextElement() method of an enumeration object returns a reference to an object, that reference will always be of the generic type Object and it will normally be necessary for you to downcast it to its true type in order to do much with it that is useful.
As mentioned earlier, and repeated here for emphasis, an enumeration object can exist only as a partner to another object containing data to be enumerated. In other words, there is no such thing as a useful standalone enumeration object . An enumeration object exists for the sole purpose of providing its methods to enumerate another object of a specific class.
The program defines a class named MyDataStruct that creates a simple data structure consisting of an array of String data.
The class provides a method that returns an object of a class that implements the Enumeration interface (an enumeration object ).
The two methods of the Enumeration interface class can then be invoked on the enumeration object to iterate through the original data structure retrieving each data element in the structure. The enumeration object serves as a structured pathway into the object that it was instantiated to enumerate.
One of the two methods of the Enumeration interface can be used to determine if there are any elements in the data structure that haven't already been retrieved.
The other method in the Enumeration interface can be used to retrieve the next element.
In this program, the controlling class
class MyEnumerator implements Enumeration{ int count;//store iteration counter here int length;//store array length here Object[] dataArray;//store reference to data array here |
This constructor receives the information for the three critical instance
variables and stores that information in those variables.
MyEnumerator(int count,int length,Object[] dataArray){ this.count = count; this.length = length; this.dataArray = dataArray; }//end constructor |
public boolean hasMoreElements(){ return (count < length); }//end hasMoreElements |
public Object nextElement(){ return dataArray[count++]; }//end nextElement |
The next interesting code fragment is the beginning of the class definition
for a class that can maintain an array of Object references and
provide an enumerator object to methods that request it. For purposes of
illustration, this class was made very simple with the initialization of
the data in the array being hard-coded into the program.
class MyDataStruct{ String[] data;//array of refs to String objects MyDataStruct(){//constructor data = new String[4]; data[0] = "zero"; data[1] = "one"; data[2] = "two"; data[3] = "three"; }//end constructor |
You might want to go back and compare the parameters passed to the constructor with the formal argument list of the constructor defined earlier.
The first parameter is used to initialize a counter in the enumerator object (this could be hard-coded into the constructor and as such would not require a parameter).
The second parameter is the length of the array.
The third parameter is a reference to the array in the object that is
to be enumerated (this could also be formulated differently using the this
reference).
Enumeration getEnum(){ return new MyEnumerator(0,data.length,data); }//end getEnum() |
The remaining code is the code in the controlling class that
class Enum01{//controlling class public static void main(String[] args){ MyDataStruct myDataStruct = new MyDataStruct(); Enumeration myEnumeration = myDataStruct.getEnum(); while(myEnumeration.hasMoreElements()){ System.out.println(myEnumeration.nextElement()); }//end while loop }//end main() }//end controlling class |
/*File Enum01.java Copyright 1997, R.G.Baldwin This program illustrates the Enumeration interface. The program defines a class named MyDataStruct that creates a simple data structure consisting of an array of String data. The class provides a method that returns an object of a class that implements the Enumeration interface (an enumeration object ). The two methods of the Enumeration interface class can then be invoked on the enumeration object to iterate through the original data structure fetching each data element in the structure. The two methods of the Enumeration interface are: public boolean hasMoreElements() public Object nextElement() The first method can be used to determine if there are any elements in the data structure that haven't already been fetched. The second method can be used to fetch the next element. The controlling class instantiates an object of type MyDataStruct, invokes the getEnum() method to get an enumeration object , and then uses that object to interate through the data structure fetching and displaying each of the elements in the structure. The program was tested using JDK 1.1.3 under Win 95. Running this program produces the following output: zero one two three **********************************************************/ import java.util.*; //=======================================================// //The following class is used by the MyDataStruct class // to instantiate an object that implements the Enumeration // interface. class MyEnumerator implements Enumeration{ int count;//store iteration counter here int length;//store array length here Object[] dataArray;//store reference to data array here //-----------------------------------------------------// //Constructor MyEnumerator(int count,int length,Object[] dataArray){ this.count = count; this.length = length; this.dataArray = dataArray; }//end constructor //-----------------------------------------------------// //This method defines one of the methods that are // declared in the Enumeration interface. public boolean hasMoreElements(){ return (count < length); }//end hasMoreElements //-----------------------------------------------------// //This method defines the other method that is declared // in the Enumeration interface. public Object nextElement(){ return dataArray[count++]; }//end nextElement }//end class MyEnumerator //=======================================================// //This class can be used to instantiate a simple data // structure object that has the ability to provide an // enumeration object to a using program. class MyDataStruct{ String[] data; //-----------------------------------------------------// MyDataStruct(){//constructor //Hard code the data for illustration purposes only data = new String[4]; data[0] = "zero"; data[1] = "one"; data[2] = "two"; data[3] = "three"; }//end constructor //-----------------------------------------------------// //This method will return an enumeration object to a // using program. Enumeration getEnum(){ return new MyEnumerator(0,data.length,data); }//end getEnum() //-----------------------------------------------------// }//end class MyDataStruct //=======================================================// class Enum01{//controlling class public static void main(String[] args){ //Instantiate an object of type MyDataStruct MyDataStruct myDataStruct = new MyDataStruct(); //Get an enumeration object that describes the object // of type MyDataStruct Enumeration myEnumeration = myDataStruct.getEnum(); //Use the enumeration object to iterate and display // each element in the object of type MyDataStruct. while(myEnumeration.hasMoreElements()){ System.out.println(myEnumeration.nextElement()); }//end while loop }//end main() }//end controlling class //=======================================================// |
This is a very handy class in that it provides the convenience of indexed access and at the same time does not confine you to the use of an array whose size is established at compile time.
Two terms are important when discussing objects of the Vector class are capacity and capacityIncrement.
The capacity specifies how many objects can be stored in the Vector object at its current size, and is always at least as large as the number of objects stored in the Vector object (elementCount). Whenever the capacity needs to be increased, it increases in chunks the size of capacityIncrement.
There are three overloaded constructors that allow you to control how the object is constructed in terms of initial capacity and capacityIncrement. You should take a look at the options in the JDK documentation.
There are a large number of methods that allow you to use a Vector
object. A sampling of some of those methods follows. You should review
the remaining methods in the JDK documentation package.
|
A hashtable stores object references by mapping keys to values. Any non-null object can be used as a key or as a value.
Objects used as keys in a hashtable must implement the hashCode() method. This is a method that converts an object into a (hopefully) unique identifier by way of applying a mathematical algorithm to the object. hashCode() is a method in the Object class and a default version is inherited by all classes in Java.
Many of the classes in the standard Java API override the hashCode() method for objects of that class. This includes the String class that we will be using for key values in a subsequent sample program.
Similarly, objects used as keys in a hashtable must implement the equals() method. The equals() method is defined in the Object class and overridden by many classes (including String) in the standard Java API.
Two terms of interest when using hashtables are capacity and load factor, because these terms affect the efficiency of the object relative to storing and retrieving objects. You can find a more detailed discussion of these terms in the JDK documentation.
So, the bottom line is that when you want to store an object in a hashtable, you provide two objects. One is used as a key and the other is stored as a value. To retrieve the object that has been stored, you simply provide the key again, and the code in the method retrieves and returns the object that was stored as a value.
All value objects are typed as the generic type Object.
There are three overloaded Hashtable constructors that allow you to instantiate Hashtable objects for different values of capacity and load factor. You should take a look at your options in the JDK documentation in this regard.
As with Vector, there are quite a few of methods available to
help you use hashtables. A sampling of these methods follows. You should
review the remaining methods in the JDK documentation.
|
In addition, it illustrates some other important Java programming concepts such as registering a list of objects for some particular purpose, processing all the objects on the list of registered objects, working at the generic Object level and downcasting when needed, etc.
The program is fairly long and somewhat complex, so we will take it in small steps.
A controlling class is used to used to test the program. The main() method of the controlling class instantiates some objects containing the names, ages, and weights of several people.
The main method of the controlling class also instantiates an object which serves as a manager for comparing these objects in pairs to report which is younger and which is lighter.
A method named registerPair() of the CompareManager class is invoked to register three pairs of objects for later comparison.
These actions are shown in the following code fragment.
public static void main(String[] args){ //Instantiate a manager to handle the comparisons CompareManager compareManager = new CompareManager(); //Register three pairs of data objects with the // manager compareManager.registerPair(new Data("Tom",65,180), new Data("Dick",60,170)); compareManager.registerPair(new Data("Harry",40,160), new Data("Dick",60,170)); compareManager.registerPair(new Data("Harry",40,160), new Data("Tom",65,180)); |
The manager creates a list of pairs of such objects as they are submitted (registered), and when requested to do so, compares and reports on all of the pairs contained in the registered list. (Actually, to keep things simple, the manager encapsulates each pair in an object and registers that object).
Therefore, this program illustrates the type of operation often referred to as registering objects, and then processing all of the registered objects upon request.
Registration lists occur in many different kinds of operations in Java such as event handling, Model-View- Controller using Observable, etc.
Note that all of the objects in this program are handled as generic Object types and downcast to the required type when needed.
Therefore, this program also illustrates the use of downcasting from Object to actual types in addition to the concepts and mechanics of registration.
When the controlling class asks the manager to perform the comparisons on all the objects in the list of registered objects, that request is made on the basis of a comparison of either AGE or WEIGHT. A class named CompareHow is defined for the sole purpose of defining symbolic constants for AGE and WEIGHT. This class also defines a symbolic constant for INVALID that is used to confirm that the program works as expected when a request is made to compare on an INVALID basis.
The next code fragment shows the main() method in the controlling
class asking the CompareManager object to compare all of the registered
pairs of objects and to report on the results. Note that three calls to
compareAll() are made, one for each symbolic constants.
compareManager.compareAll(CompareHow.AGE); compareManager.compareAll(CompareHow.WEIGHT); compareManager.compareAll(CompareHow.INVALID); |
There is a small class definition for a class named Data. This class is used to encapsulate the name, age, and weight data for a person in an object. The code for this class is too simple to merit being shown in this section. You can see it in the complete program listing that follows near the end of the lesson.
Likewise, as mentioned earlier, there is a small class definition for a class named CompareHow whose sole purpose is to define the symbolic String constants for AGE, WEIGHT, and INVALID. These symbolic constants are used later as keys in a hashtable. Again, this class is too simple to merit being shown in this section.
An interface named Comparable is defined which declares a method
named comparePair(). This method is implemented in several different
classes in the program.
interface Comparable{ public void comparePair(String how, Object obj1, Object obj2); }//end Comparable interface |
Note that the definition of the Comparable interface would also have been a good place to define the symbolic constants mentioned above since the definition of constants is allowed in an interface.
The manager class (which is instantiated by and communicated with by the controlling class) is named CompareManager. This class is used to
The list of registered pairs of objects is maintained in an object of type Vector. Therefore, this program illustrates the use of the Vector class for maintaining a list of registered objects.
The following code fragment shows the beginning of the definition of
the CompareManager class where the instance variables for the references
to the CompareTool object and the Vector object are declared.
Note that the reference to the CompareTool object is maintained
as a generic Object type.
class CompareManager{ Object compareTool; Vector myListOfObjects; |
An inner-class is used for this purpose as shown in the next code fragment.
Although it is a very simple class, the fact that it is an inner class
probably merits displaying and discussing it in this section.
class PairOfObj{ Object obj1; Object obj2; PairOfObj(Object obj1,Object obj2){//constructor this.obj1 = obj1; this.obj2 = obj2; }//end constructor }//end inner-class PairOfObj |
CompareManager(){//constructor for a manager object this.compareTool = new CompareTool(); myListOfObjects = new Vector(); }//end constructor |
No provisions are made to remove objects from the list of registered
objects as is frequently the case when a registration list is used to maintain
a list of registered objects. Obviously, this wouldn't be difficult given
the methods that are available to manipulate the contents of the Vector
object. Also, this registration method doesn't make any effort to prevent
duplicated objects in the list which is sometimes done.
public void registerPair(Object obj1,Object obj2) { this.myListOfObjects.addElement( new PairOfObj(obj1,obj2)); }//end registerPair |
The compareAll() method invokes the elements() method on the Vector object which instantiates and returns an object that implements the Enumeration interface. In other words, it returns an enumeration object. On the basis of the previous discussion, you should be aware of what this enumeration object is, and what can be done with it.
Methods of the Enumeration interface are then used to extract
each of the composite objects from the list of registered objects. Each
of the objects in the pair is then extracted from the registered composite
object, and passed, along with a string parameter specifying how to perform
the comparison, to a method named comparePair() which is a method
of the CompareTool object described earlier. Note that comparePair()
is declared in the Comparable interface and must be defined in all
classes that implement that interface.
public void compareAll(String how){ Enumeration myEnum = myListOfObjects.elements(); while(myEnum.hasMoreElements()){ Object aPairOfObj = myEnum.nextElement(); ((Comparable)compareTool).comparePair(how, ((PairOfObj)aPairOfObj).obj1, ((PairOfObj)aPairOfObj).obj2); }//end while loop }//end compareAll }//end CompareManager class |
That is the end of the compareAll() method and the end of the CompareManager class as well.
Now we will discuss the CompareTool class from which an object is instantiated to actually perform the comparison between two objects.
This is a little tricky, so you may need to pay close attention.
This class contains two inner-classes named AgeCompare and WeightCompare. Each of these classes implements the Comparable interface, and therefore defines a method named comparePair().
However, the comparePair() methods differ between the two classes. In one case, the code is designed to compare two objects on the basis of the instance variable named age. In the other case, the method is designed to compare two objects on the basis of the instance variable named weight.
These are the two methods that are ultimately invoked to make the actual comparisons, with the choice between methods being based on a String object that is passed in with the objects that are to be compared. The String object specifies either AGE or WEIGHT.
The following code fragment shows the beginning of the CompareTool class and the declaration of a reference variable to a Hashtable object along with the instantiation of that object.
This code fragment also shows one of the inner-classes named AgeCompare discussed above. The two inner-classes are very similar, so only one is shown here. You can view the other one in the complete program listing near the end of this lesson.
Note that these inner classes define a method having the same name,
comparePair(), as a method in their parent class. Also note that
in all three cases this method implements the Comparable interface.
However, the implementation in all three cases is different depending on
the class in which is is defined and the needs of objects of that class.
The code to actually make the comparisons is straightforward, once you
get past the downcasting requirements.
class CompareTool implements Comparable{ private Hashtable myHashTable = new Hashtable(); //_____________________________________________________// private class AgeCompare implements Comparable { public void comparePair(String how,Object obj1, Object obj2){ System.out.println("In AgeCompare method"); Data temp1 = (Data)obj1;//Cast incoming objects to Data temp2 = (Data)obj2;// the correct type. //Make the comparison on age if(temp1.age<temp2.age) System.out.println(temp1.name + " is younger than " + temp2.name); else System.out.println(temp1.name + " is not younger than " + temp2.name); }//end trace() }//end inner-class AgeCompare |
One object that is stored in the Hashtable is a reference to an object of type AgeCompare along with a key value of AGE.
The other object that is stored in the Hashtable is a reference to an object of type WeightCompare along with a key value of WEIGHT.
Make certain that you understand that these two objects are instantiated
from the inner classes described above and what that implies.
public CompareTool(){//constructor myHashTable.put( CompareHow.AGE, new AgeCompare() ); myHashTable.put( CompareHow.WEIGHT, new WeightCompare() ); }//end constructor |
Therefore, this program illustrates the use of a Hashtable object to store and retrieve references to objects containing useful instance methods (as opposed simply to data values) on the basis of a key value.
(This concept may seem very foreign to you at this point, but we will be making heavy use of the concept when we explore the use of the invoke() method of the Method class in the reflection API around lesson 262.)
The CompareTool class implements the Comparable interface, meaning that it defines the method named comparePair() also. This is the method that is called by the object of the CompareManager class to compare two objects. In addition to the references to the two objects that are to be compared, this method also receives a String parameter specifying how to make the comparison: AGE or WEIGHT.
However, this method doesn't actually make the comparison. Rather, it first tests to confirm that the incoming String constant is contained as a key in the Hashtable. If it is a valid key value, it invokes the get() method on the Hashtable object, passing that key as a parameter, and in return receives a reference to an object associated with that key. The referenced object contains a method of the same name, comparePair(). The comparePair() method of the referenced object is invoked to perform the actual comparison.
Therefore, by using the incoming key value to access the Hashtable object, this method gains access to another method that is designed to perform the comparison in a manner that is consistent with the key value.
This is an interesting concept on selection. In the case of this simple program, only two different methods are represented by objects in the Hashtable. However, there could be dozens, hundreds, or even thousands of different methods represented by objects in the hashtable, and selection among them could be made simply on the basis of the key value associated with each. In effect, this is an approach to selection that goes beyond if else and switch case.
Note that when this method named comparePair() invokes the method
named comparePair(), it is invoking a method that is defined in
one of the objects stored in the hashtable. It is not making a recursive
call on itself.
public void comparePair(String how, Object obj1, Object obj2){ if(myHashTable.containsKey(how)){ Object theMethod = myHashTable.get(how); ((Comparable)theMethod).comparePair(how,obj1,obj2 ); }//end if else System.out.println( "Invalid Key, could throw exception here"); }//end comparePair() |
As mentioned earlier, we will be making heavy use of this concept when we use of the invoke() method of the Method class in the reflection API to create smart event adapters in the Advanced portion of the tutorial around lesson 262.
If the incoming String parameter is not contained as a key in the Hashtable, an "Invalid Key" message is displayed and no attempt is made to compare the objects. This would be a good place to throw an exception.
As mentioned earlier, this particular program isn't intended to be useful for anything other than to illustrate the use of the Vector, and Hashtable classes along with the Enumeration interface, and also to illustrate some other important concepts such as creating and maintaining a list of registered objects, downcasting from Object to true type, etc. It is also intended to get you prepared to understand what you will encounter in the Advanced portion of the tutorial in relation to the reflection API.
The output from the program is contained in the comments at the beginning of the program listing.
/*File Hash01.java Copyright 1997, R.G.Baldwin This program is not intended to accomplish anything particularly useful other than to illustrate how to use the Vector and Hashtable, and the Enumeration interface. This program was tested using JDK 1.1.3 under Win95. The output from the program is: In AgeCompare method Tom is not younger than Dick In AgeCompare method Harry is younger than Dick In AgeCompare method Harry is younger than Tom In WeightCompare method Tom is not lighter than Dick In WeightCompare method Harry is lighter than Dick In WeightCompare method Harry is lighter than Tom Invalid Key, could throw exception here Invalid Key, could throw exception here Invalid Key, could throw exception here **********************************************************/ import java.util.*; //=======================================================// //This is the controlling class used to test everything // else. class Hash01{ public static void main(String[] args){ //Instantiate a manager to handle the comparisons CompareManager compareManager = new CompareManager(); //Register three pairs of data objects with the // manager compareManager.registerPair(new Data("Tom",65,180), new Data("Dick",60,170)); compareManager.registerPair(new Data("Harry",40,160), new Data("Dick",60,170)); compareManager.registerPair(new Data("Harry",40,160), new Data("Tom",65,180)); //Request comparison of all pairs of objects on the // basis of age and weight (separately). Also // request comparison on the basis of an invalid // parameter. compareManager.compareAll(CompareHow.AGE); compareManager.compareAll(CompareHow.WEIGHT); compareManager.compareAll(CompareHow.INVALID); }//end main }//end class Hash01 //=======================================================// //This is the class used to package the data for // submission to the comparison manager. class Data{ String name; int age; int weight; Data(String name,int age,int weight){ this.name = name; this.age = age; this.weight = weight; }//end constructor }//end class Data //=======================================================// //Define some string constants that are used later as // keys in a hash table. class CompareHow{ public static final String AGE = "AGE"; public static final String WEIGHT = "WEIGHT"; public static final String INVALID = "INVALID"; }//end class CompareHow //=======================================================// //Define the Comparable interface. Note that it declares // the method named comparePair() that is defined in // several classes that implement the interface. interface Comparable{ public void comparePair(String how,Object obj1, Object obj2); }//end Comparable interface //=======================================================// //This class is used to manage the process of comparing // pairs of objects class CompareManager{ //Stores a reference to an object that does the work // of comparing objects on the basis of a String // parameter that define how the objects are to be // compared. Object compareTool; //Stores a list of references to objects each of which // contains a pair of objects to be compared. Vector myListOfObjects; //_____________________________________________________// //Define an inner class of the CompareManager class // that is used to package a pair of incoming // objects into a single object for storage in a // Vector object. class PairOfObj{ Object obj1; Object obj2; PairOfObj(Object obj1,Object obj2){//constructor this.obj1 = obj1; this.obj2 = obj2; }//end constructor }//end inner-class PairOfObj //_____________________________________________________// CompareManager(){//constructor for a manager object //Instantiate a tool object which will be used to // actually perform the comparisons this.compareTool = new CompareTool(); //Instantiate a Vector object to contain a list of // registered objects myListOfObjects = new Vector(); }//end constructor //-----------------------------------------------------// //This method maintains a list of registered objects // in a Vector object where each registered object // contains a pair of objects that are to be compared // later all at the same time. public void registerPair(Object obj1,Object obj2) { this.myListOfObjects.addElement( new PairOfObj(obj1,obj2)); }//end registerPair //-----------------------------------------------------// //This method compares all the pairs of objects contained // in the list of registered objects. The comparison is // performed on the basis of the how parameter (age or // weight). public void compareAll(String how){ //Create an enumeration object for the objects in the // list of registered objects. Enumeration myEnum = myListOfObjects.elements(); //Use the enumeration object to process all the objects // in the list of registered objects. Each registered // object contains a pair of objects that are to be // compared. while(myEnum.hasMoreElements()){ //Get the next registered object Object aPairOfObj = myEnum.nextElement(); //Extract and compare the pair of objects contained // in the registered object. ((Comparable)compareTool).comparePair(how, ((PairOfObj)aPairOfObj).obj1, ((PairOfObj)aPairOfObj).obj2); }//end while loop }//end compareAll }//end CompareManager class //=======================================================// //This class is used to instantiate an object which // performs the actual comparisons based on a parameter // named how and using references to methods that are // stored in a hash table along with key values that // match the parameter named how. The parameter named // how is used to fetch a reference to a method from the // hash table and that reference is used to invoke the // method to which it refers. class CompareTool implements Comparable{ //Store references to different comparison methods in // a hash table for later reference. private Hashtable myHashTable = new Hashtable(); //_____________________________________________________// //This inner class contains one of the methods used to // compare objects. This one is designed to compare on // the basis of the instance variable named age. Note // that the name of the method in this inner class is // the same as the name of a method in the parent class // of this class and is also the same as the method // declared in the interface named Comparable. private class AgeCompare implements Comparable { public void comparePair(String how,Object obj1, Object obj2){ System.out.println("In AgeCompare method"); Data temp1 = (Data)obj1;//Cast incoming objects to Data temp2 = (Data)obj2;// the correct type. //Make the comparison on age if(temp1.age<temp2.age) System.out.println(temp1.name + " is younger than " + temp2.name); else System.out.println(temp1.name + " is not younger than " + temp2.name); }//end trace() }//end inner-class AgeCompare //_____________________________________________________// //This inner class contains one of the methods used to // compare objects. This one is designed to compare on // the basis of the instance variable named weight. Note // that the name of the method in this inner class is // the same as the name of a method in the parent class // of this class and is also the same as the method // declared in the interface named Comparable. private class WeightCompare implements Comparable { public void comparePair(String how,Object obj1, Object obj2){ System.out.println("In WeightCompare method"); Data temp1 = (Data)obj1;//Cast incoming objects to Data temp2 = (Data)obj2;// the correct type. //Make the comparison on weight if(temp1.weight<temp2.weight) System.out.println(temp1.name + " is lighter than " + temp2.name); else System.out.println(temp1.name + " is not lighter than " + temp2.name); }//end trace() }//end inner-class WeightCompare //_____________________________________________________// //This is the constructor for the CompareTool class. // It instantiates two objects, each containing a // method named comparePair() and stores references to // them in the hash table, each with a different key. // The key values are designed to match the how // parameter that is passed in to specify how the // comparison is to be performed. Later, the how // parameter is used to fetch the reference to a // particular method and that reference is used to // invoke the method. public CompareTool(){//constructor //Initialize myHashTable and store references to // methods in a hash table using string constants from // the CompareHow class as keys. myHashTable.put( CompareHow.AGE, new AgeCompare() ); myHashTable.put( CompareHow.WEIGHT, new WeightCompare() ); }//end constructor //-----------------------------------------------------// //This is the method that is called to compare two // objects on the basis of the how parameter. //Note that the name of this method is the same as the // name of a method in each of the inner classes, and // is also the same as the name of the method declared // in the interface named Comparable. public void comparePair(String how, Object obj1, Object obj2){ //Use incoming how parameter to extract the reference // to the correct method from the hash table to use for // this comparison and assign the reference to a local // variable named theMethod. Test to confirm that the // value of the how parameter is actually a key in the // hashtable. If not, simply display a message. Note // that this would be a good place to throw an // exception. if(myHashTable.containsKey(how)){ Object theMethod = myHashTable.get(how); //Use the local variable named theMethod to invoke // the correct comparison method on the incoming // objects. //Note that this is the invocation of a method // named comparePair() that is defined in one of // the inner classes of this class and is contained // in the object referenced in the hash table. It // is not a recursive call to this version of // comparePair(). ((Comparable)theMethod).comparePair(how,obj1,obj2 ); }//end if else System.out.println( "Invalid Key, could throw exception here"); }//end comparePair() //-----------------------------------------------------// }//end CompareTool class //=======================================================// |
/* File SampProg153.java Copyright 1998, R.G.Baldwin From lesson 76 Without viewing the solution that follows, write a Java application that uses the Vector class to implement a LIFO stack. Make certain that the data in the stack is available only on a LIFO basis using the methods shown below. Make the stack class capable of accommodating objects of any type. Throw an exception if the user attempts to pop an empty stack. Methods: isEmpty() - returns true if this stack is empty. pop() - Removes and returns the object from the top of this stack. push(Object) - Pushes an item onto the top of this stack. This program was tested using JDK 1.1.3 under Win95. The output from the program is: Mary Jones Sue Williams Joe Johnson Dick Baldwin java.util.NoSuchElementException **********************************************************/ import java.io.*; import java.util.*; //=======================================================// class MyStack{ //Note that this class contains and does not extend // Vector. private Vector stack = new Vector(); //-----------------------------------------------------// boolean isEmpty(){ return stack.isEmpty(); }//end isEmpty() //-----------------------------------------------------// void push(Object item){ stack.addElement(item); }//end push() //-----------------------------------------------------// Object pop()throws NoSuchElementException{ Object temp = stack.lastElement(); stack.removeElementAt((stack.size()-1)); // stack.removeElementAt(stack.lastIndexOf(temp)); return temp; }//end pop() //-----------------------------------------------------// }//end class MyStack //=======================================================// class SampProg153{//controlling class public static void main(String[] args){ MyStack stack = new MyStack(); stack.push(new TestClass("Dick","Baldwin")); stack.push(new TestClass("Joe","Johnson")); stack.push(new TestClass("Sue","Williams")); stack.push(new TestClass("Mary","Jones")); try{ while(!stack.isEmpty()) System.out.println(stack.pop()); //Try to pop an empty stack System.out.println(stack.pop()); }catch(NoSuchElementException e){System.out.println(e);} }// end main }//end class SampProg153 definition //======================================================// class TestClass{ String first; String last; TestClass(String first, String last){//constructor this.first = first; this.last = last; }//end constructor //----------------------------------------------------// public String toString(){ return first + " " + last; }//end toString() }//end TestClass //======================================================// |
/* File SampProg154.java Copyright 1998, R.G.Baldwin From lesson 76 Without viewing the solution that follows, write a Java application that uses the Vector class to implement a LIFO structure similar to a stack. This structure has set and get methods that mirror the typical push and pop methods in a stack. However, this structure also has an enumerator that allows you to access the individual elements in the structure in sequential order, and to modify them in the process. Make the structure class capable of accommodating objects of any type. Throw an exception if the user attempts to get an element from an empty structure. Methods: isEmpty() - Returns true if the structure is empty. get() - Removes and returns the object from the top of the structure. set(Object) - Stores an element onto the top of the structure. This program was tested using JDK 1.1.3 under Win95. Typical output from the program is: Set the structure Enumerate and modify the structure Dick Baldwin Joe Johnson Sue Williams Mary Jones Get the modified structure Mary Modified Sue Modified Joe Modified Dick Modified java.util.NoSuchElementException **********************************************************/ import java.io.*; import java.util.*; //=======================================================// class MyStructure{ private Vector structure = new Vector(); //-----------------------------------------------------// boolean isEmpty(){ return structure.isEmpty(); }//end isEmpty() //-----------------------------------------------------// void set(Object item){ structure.addElement(item); }//end set() //-----------------------------------------------------// Object get()throws NoSuchElementException{ Object temp = structure.lastElement(); structure.removeElementAt(structure.size()-1); return temp; }//end get() //-----------------------------------------------------// Enumeration getEnumerator(){ return new Enumerator(this); }//end getEnumerator() //-----------------------------------------------------// int getSize(){ return structure.size(); }//end getSize() //-----------------------------------------------------// Object getElement(int which){ return structure.elementAt(which); }//end getElement() //-----------------------------------------------------// }//end class MyStructure //=======================================================// class Enumerator implements Enumeration{ MyStructure theStructure; int elementCounter; //-----------------------------------------------------// Enumerator(MyStructure theStructure){//constructor this.theStructure = theStructure; elementCounter = 0; }//end constructor //-----------------------------------------------------// public boolean hasMoreElements(){ return (elementCounter < theStructure.getSize()); }//end hasMoreElements //-----------------------------------------------------// public Object nextElement(){ return theStructure.getElement(elementCounter++); }//end nextElement }//end class Enumerator //=======================================================// class SampProg154{//controlling class public static void main(String[] args){ MyStructure structure = new MyStructure(); System.out.println("Set the structure"); structure.set(new TestClass("Dick","Baldwin")); structure.set(new TestClass("Joe","Johnson")); structure.set(new TestClass("Sue","Williams")); structure.set(new TestClass("Mary","Jones")); System.out.println( "Enumerate and modify the structure"); Enumeration enum = structure.getEnumerator(); TestClass temp; while(enum.hasMoreElements()){ temp = (TestClass)enum.nextElement(); //Display the element System.out.println(temp); //Modify the element temp.last = "Modified"; }//end while loop System.out.println("Get the modified structure"); try{ while(!structure.isEmpty()) System.out.println(structure.get()); //Try to get element from an empty structure System.out.println(structure.get()); }catch(NoSuchElementException e){ System.out.println(e); }//end catch }// end main }//end class SampProg154 definition //=======================================================// class TestClass{ String first; String last; TestClass(String first, String last){//constructor this.first = first; this.last = last; }//end constructor //----------------------------------------------------// public String toString(){ return first + " " + last; }//end toString() }//end TestClass //======================================================// |
-end-