CS210 Tues., Jan 31: pa1 is available.

Return quals, call roll to locate new people.

Note: solution to qual to help start pa1, an extension.

Solution uses ArrayList<Box>  and ArrayList<Bin>--study this if you are new to generics.

Last time we looked at Weiss’s examples in Chap 4, with a handout. 

We saw how a Shape class could organize the similarities of classes for circles, rectangles, etc., ending up with an abstract class Shape, that expresses the idea that all shapes have area formulas and perimeters, even though they are calculated differently for different shapes.

Then we turned the abstract class Shape into an even more abstract interface, called AShape.java to keep them differentiated.

Multiple Inheritance—not in Java!

Suppose windows come in different shapes, so it seems natural to say that a certain shaped window IS-A Window and IS-A Shape.  If we could express that in Java, we would be using multiple inheritance.  But Java doesn’t have this feature, because of all the problems it caused in C++.  What can we do?

We can use interfaces, the purest form of abstract class (not even really a “class” according to the Java Lang. Spec.)  These provide a way of specifying pure API information, no implementation (code) at all.  Then we are allowed to have a real class (not an interface) implement multiple interfaces, describing multiple aspects, like window-ness and shape.

window actions: resize, repaint, close…

shape actions:  area, perimeter, semiperimeter

Can imagine two interfaces describing these, and

class ShapedWindow implements AShape, Window …

or if Window is a class,

class ShapedWindow extends Window, implements Shape …

or vice versa, but not extends both, that would be the disallowed multiple inheritance.

Shape as interface:  from handout of last class—

public interface AShape
{
    double area( );
    double perimeter( );
    double semiperimeter( );
}

Now for a Window interface (with PlainWindow and FancyWindow implementing it) and AShape, we could have:

class ShapedWindow implements Window, AShape {

double area() { … }           //implements area, perimeter, semiperimeter, also resize, repaint, ...

}

 May not be that useful as a concrete class—where are Circle and Rectangle, and PlainWindow,  the ones that know the relevant formulas? 

We can change ShapedWindow to an abstract class, leaving area and perimeter abstract, and have subclasses based on shape and window-type:

abstract class ShapedWindow implements Window, AShape {
  protected Window myWindow;  // init'd in CircularPlainWindow with "new PlainWindow(...)"
                              // or in SquareFancyWindow with "new FancyWindow(...)"
  protected AShape myShape;  // init’d in CircularPlainWindow constructor with “new Circle(radius)”
                            // or in SquareFancyWindow with "new Square(sideLength)", etc.
...
 double area() {  return myShape.area(); }
 repaint() { return myWindow.repaint(); }
 …
}

class CircularPlainWindow extends ShapedWindow {
     
  CircularWindow(double radius, ...) {  ..., myShape = new Circle(radius); ... }

}

 Here CircularWindow is known to implement AShape, because ShapedWindow does.

 Then we end up with objects that have concrete classes of both Window and Shape in them, so they can do both kinds of actions.

 But back to simpler uses of interfaces—they can express pure APIs, separate from implementation.

Interfaces

Interfaces are very helpful for description of what classes can do.  For example, ArrayList is a class that implements Collection and List—we’ll be studying these interfaces.  For Collection, see pg. 192 in Weiss or look it up in JBuilder help (try this out.)  Anything that implements Collection must provide all the methods listed: size, isEmpty, …  Thus we know quite a bit about ArrayList just from this quick description.

Study example of Comparable in book, pp. 116-117, amd pg. 129-130.  We’ll see Collection, Iterator, Map, …pretty soon.

4.6.2, p. 125 Wrappers for Primitive types (list of these, pg. 7)

Primitive type (or just "primitive")   Wrapper for it, making an object

int                 Integer

double          Double

char              Character

boolean         Boolean

Look these up in Java docs, see useful facts in these classes: Integer.MAX_VALUE  and Character.isWhiteSpace for example.

Use these in generic classes, like ArrayList<Integer>--need real object classes for use in <>.

 Generics--a big subject, can't review all of it today.

Let's start with the most important for our use--generic ArrayList, as used in qual solution.  

In Bin, we need a collection of Box objects, so we use ArrayList<Box> as a field of Bin.

Design idea:   A bin contains a collection of boxes.

Implementation:  Bin has a field of type ArrayList<Box>

public class Bin {
  private ArrayList<Box> boxes = new ArrayList<Box>();
  ...

Later in addBox(Box b)
      boxes.add(b);
With this setup, we could access individual Box:
         Box firstBox = boxes.get(0);

Note no cast is needed, because boxes knows its element type.

With ArrayList<Integer>, the objects are held as Integers in the ArrayList, but we have a choice when we get them out:

ArrayList<Integer> arr = new ArrayList<Integer>();  // as on pg. 128
Integer val1 = arr.get(0);

int val2 = arr.get(0);

Chap 5:  Big-Oh Algorithm Analysis

Look at pg. 149—graphs of running times.

T = O(1):  T is bounded by some constant for large N

T = O(N):  T is bounded by a linear function of N, for large N, so eventually, T < kN for some k

T = O(N2)  T is bounded by a quadratic function of N, for large N, so T < k N2

 

Polynomials for running time:  T = 3 n2 + 5n + 100

For large n, the highest power dominates, we say   T = O(n2)

Fractional powers   sqrt(n)  = n1/2 fits in between 1 and n.

Powers in general  np For p > 0, these grow for large n, faster for larger p.

Exponential  2n doubles for each n value:  210 = 1024,  211 = 2048 etc.

So if T = O(2n), running time doubles for each unit increase in input size.

Grows faster than any power.  Usually the worst we see in practice.

Log = inverse of exponential, slowest we normally see.

Base 2 log:  log 2 = 1, log 1024 = 10, log 2048 = 11

See that we have to double the n to get the result to increase by 1.

T = O(log n) is almost as good as O(1)—very slow growth for large n

Simple loops, i from 1 to n, have n passes.  If body takes O(1), whole loop takes n*O(1) = O(n).

Double loops, 1 to n two ways, body O(1), take n*n*O(1) = O(n2).