In this section, we focus on the design and implementation of the keySet collection view for a map. The entrySet collection view will be discussed in Chapter 21 when we implement the HashMap collection. Understanding the difference between a collection and a collection view is critical. A collection is an object consisting of data and operations that specify elements and methods to access and update their values. A collection-view object doesn't have its own data. It uses the data in the backing collection. The view object does have operations, however, but these are tied to the operations in the backing collection. They have the effect of accessing and updating elements in the backing collection. A keySet view for a map has operations that reference the key fields among the key-value elements in the collection. The keySet methods implement the Set interface but with the add() operation disallowed by having the method throw an exception.
Examining a View :
The concept of a view is relatively straightforward. The implementation is more difficult since it involves specialized concepts and techniques. A very simple example illustrates the techniques. Extending them to the keySet collection view becomes a matter of details.
The class StoreOneTwo has data members one and two that hold integer values. A constructor initializes the values and toString() provides a representation of the object in the form one=two. The class defines the method setOneTwo() that allow the programmer to update the instance variables. Associated with the class we create an interface called View. The interface defines methods get() and set(), which may be used by a view object to access and update a field in the backing object :
The StoreOneTwo class defines the method viewOne(), which returns a View object that is associated with filed one in a StoreOneTwo object. The method is responsible for creating an object of type View and for implementing the interface methods as they pertain to the variable one in StoreOneTwo, the backing collection. The following is an implementation of the StoreOneTwo class. Only the method header for viewOne() is included. Its implementation will be the focus of this section :
Implementing a View :
In the StoreOneTwo class, the method viewOne() returns an object that implements the View interface. The object does not have its one data; rather, it relies on access to the variable one in a StoreOneTwo object. To create the View object returned by viewOne(), we use an anonymous inner class; that is, an inner class that does not have a name. An anonymous inner class combines the declaration of an inner class with the creation of an instance of the class in one step. In our example, the anonymous inner-class declaration creates a variable that is an instance of a class that implements the View interface.
Prior to its implementation of the method viewOne(), the StoreOneTwo class declares the instance variable viewObj of the type View and assign it the value null. The variables is instantiated in the method viewOne() as an object of anonymous class type that implements the View interface. The body for the anonymous class is provided in a block that accompanies the declaration of viewObj. The anonymous class implements, View and so must implement the methods get() and set(), which access the variable one in the outer class.
In the implementation of viewOne(), the instance variable viewObj is instantiated with the operation new View(). This looks strange since a variable cannot be instantiated as an interface object. In fact, viewObj is not an interface object but rather an object of anonymous class type that implements View :
The keySet Collection View :
In the TreeMap class, the method keySet() returns a collection view that implements the Set interface. Using the approach discussed in the previous section, we implement the method keySet() by creating an anonymous inner-class object and making it the return value.
We must implement the methods defined in the interface. Remember that all of the methods work on the backing map collection. The Set methods size(), isEmpty() and clear() have implementations that use the corresponding TreeMap methods. Note that when you use "this" in an inner class, it references the inner-class object! To reference "this" for the enclosing class, preface it by the name of the enclosing class followed by the "." operator. For instance, TreeMap.this.size() refers to the method size() in the TreeMap class. Here is the implementation for size() in the collection view :
The methods contains() and remove() have a single Object argument. In the keySet view, the argument represents a key in a key-value entry in the map. Their implementations use corresponding TreeMap methods that require the key for their argument.
The Set method add() requires special attention. Since it is in the interface, the method must be implemented. However, the Set add() operation makes no sense in the collection view. Inserting an object in KeySet should correspond to adding a key-value entry in the map. The object would become a key without any associated value. The implementation of add() in KeySet throws an UnsupportedOperationException, which has the effect of making the operation invalid.
The KeySet and the entrySet collection view provide an iterator that scans the keys in the map. In the implementation of keySet(), the method iterator() returns an Iterator object of type KeyIterator. In the implementation of entrySet(), the return Interator object is of type EntryIterator. Both of these Iterator classes must implement next(), hasNext() and remove(). We simplify the take be creating a single generic iterator class InteratorImpl
Supplement :
* Java In a Nutshell : Anonymous Classes
沒有留言:
張貼留言