CS210 Feb. 9:  collect hw1, questions on pa1?

Using Comparable<T> in methods

Recall from last time our example of Comparable<Shape> over the Shape hierarchy:  it was easy to implement it once and for all in the base class, and then it was usable for all the subclasses, that is, we could say "Circle implements Comparable<Shape>", and do circle.compareTo(sqr), etc, to compare areas.  Comparison by area is the "natural order" for these Shape objects.

There's only one problem:  because of Java parametrized type rules, we can't say "Circle implements Comparable<Circle>" from this setup, because A IS-A B does NOT imply Comparable<A> IS-A Comparable<B>.  This only bothers us when we want to write generalized binarySearch or findMax algorithms, or othe generic algorithms, but we need to be able to do that.
Why is the setup for findMax, pg. 135, so complicated?
Answer, because there are two types here involved in the type setup, AnyType and Comparable, and one is itself parametrized.


This is the same situation as binarySearch, so it is important.

Java has to come up with some syntax to describe the relationship between AnyType and Comparable<>..
But remember, if AnyType is Square, implementing Comparable<Shape>, we can't say "Square implements Comparable<Square>" even though compareTo is fully functional for Squares.

Java lets us wildcard the usable Comparable<T>'s here. We can ask to use Comparable<ST> for any class or interface ST super to T in the hierarchy, i.e., where T IS-A ST.
This is always logically justified: if T IS-A ST, and implements Comparable<ST>, then it must implement compareTo<ST>, and this must accept a T, since T IS-A ST.

Now let's tackle this example of generic code:

public static <AnyType extends Comparable<? super AnyType>> int binarySearch(AnyType [] a, AnyType x)
{
... same code except a[mid] < x    is now a[mid].compareTo(x) < 0, etc.
}

Decoding this method declaration:
First locate the left parenthesis, an important signpost.  The method's parameters are to its right, until the ).
Then locate method name: binarySearch, always just before the left parenthesis.
Then locate the method return type, int, listed just before the method name.
Then any <...> "type bound", to the left of the return type.  Match up <>'s to get the whole thing.
To its left, various possible descriptive keywords.

The type bound sets up the parametrization for the method.
Here we have <AnyType extends Comparable<? super AnyType>>
                     dummy type var     Comparable<T>, where T is at or above AnyType in its hierarchy
                                     "extends" here means extends or implements  (see pp 134-135)

                      AnyType implements Comparable<something at or super to AnyType>
                      Ex:  Circle implement Comparable<Shape>

OK we now see that it's a workaround for "stupid" non-compatibility of parametrized types.
This is saying: it's OK if Circle implements Comparable<Circle>, but it's also OK if Circle implements Comparable<Shape>.  Either way, this method is willing to accept the array and do its work.

Also see the links under Resources at the end of the class web page to a Canadian overview of generics that is really hard on Sun's decisions for this ugly syntax.

If a type hierarchy is in the comparing business, the normal thing would be to have the base class like Shape be Comparable<Shape>, with appropriate compareTo methods in subclasses if necessary.  So the whole hierarchy is Comparable, as we saw implemented for Shape in the handout.
Note: a subclass that does override compareTo has to handle not only is own subtype, but also other subtypes, so in the Shape case, Square.compareTo(Shape x) has to do something with an x that is not a Square.  It can throw ClassCastException, but must make sure that the behavior is symmetric:  if  y.compareTo(x) throws, then so must x.compareTo(y).  You can see that doing compareTo correctly over a type hierarchy is difficult unless you can do it once and for all in the base class.  

If only a subclass T is Comparable<T>, not the base class, this setup for binarySearch still works for searching an array of T's.  The wildcard expression is saying either setup is OK.

Actually calling binarySearch or findMax.  Suppose findMax is in class MyUtils

        Shape [ ] shapes = { new Circle( 0.5 ), new Rectangle( 1.0, 3.0 ),
                                                new Square( 2.0 ) };
        System.out.println("compareTo returned " + shapes[0].compareTo(a[1]));
        Shape maxOne = MyUtils.findMax(shapes);

I expected to find binarySearch as on pg. 185 in the Arrays class of the JDK, but its not there.  The related version with the Comparator is there.  So again we have to imagine this in MyUtils.

                int spot = MyUtils.binarySearch(shapes, new Rectangle(4.0, 1.0));

should return spot = 2, since the area of 4 matches.  Note that shapes is ordered by area, and thus is in "natural order" as described by its Comparator..

We'll have to cover Comparators eventually, but let's leave types for now.

Chap. 6 Collection classes and interfaces

Containers—Lists, Sets, Stacks, Queues, Maps—ways to hold objects, with a specific order or not, with certain ways to get at them

Will work with JDK concrete classes ArrayList, LinkedList, TreeSet, HashSet, TreeMap, HashMap, others

Containers and Iterators—can skip to from pg. 204 to Fig. 6.8, see the resulting model if you want.

Iterators help us scan through objects in a container 

Can iterate through an array v—pg. 204

for (int i = 0; i < v.length; i++)
   do something with v[i]

for (ElementType x: v)
   do something with x

 and you know how to do this with an ArrayList<ElementType>  al—

for (int i = 0; i < al.size(); i++)
   do something with al.get(i)

for (ElementType x: al)
   do something with x

Note v[i] and al.get(i) are both O(1) in execution time—access to an array element.

Collection interface, pg. 211, parametrized by <AnyType> the element types.  Think of as generalization of ArrayList<T>.

Iterator interface—pg. 212-213 , parametrized by AnyType:  where AnyType is the element type of the Collection.

 boolean hasNext();   // the collection has a “next” object

AnyType next();        // get a ref to the next element object promised by hasNext, with the appropriate type

void remove();  // ignore for now