340 likes | 480 Views
Type Hierarchies. Type Hieararchy. Why?: Want to define family of related types. At the top of the hierarchy, a type whose spec defines behavior common to all family members Two different ways: Multiple implementations of a type: Two-level hieararchy Example: phoneBook w/ Hashtable
E N D
Type Hieararchy • Why?: Want to define family of related types. • At the top of the hierarchy, a type whose spec defines behavior common to all family members • Two different ways: • Multiple implementations of a type: • Two-level hieararchy • Example: • phoneBook w/ Hashtable • phoneBook w/ Vector • Different types do not add any new behavior • Except, each has its own constructors • Different subtypes extend behavior of their supertypes • Examples: Additional methods • Supertype’s behavior must be satisfied by subtype • Called the substitution principle • The “is” relationship • Can replace an object of the subtype whenever object of the supertype is required
Assignment • Apparent vs. actual type • Suppose Poly p1 = new DensePoly(); //the zero Poly Poly p2 = new SparsePoly(3, 20); // the Poly 3x20 • Variable of type Poly can refer to DensePoly or SparsePoly objects • Compiler does checking based on apparent type • Cannot invoke a DensePoly only method on p1 • But DensePoly dp = (DensePoly) p1; dp.densePolyMethod() … is legal Poly SparsePoly DensePoly
Dispatching • Example: Poly p1 = new DensePoly(); int n = p1.degree(); • Both Poly and DensePoly have their own version of the degree() method • Example Static Poly diff(Poly p) { //differentiates p int g = p.degree(); ... } • Dispatching: Figuring out which one to call • Checking done based on apparent type • Execution during run-time based on actual type
Defining a Type Hierarchy • First step: Define type at top of hierarchy • May not be a complete specification • May lack constructors, some methods • Subtypes • Provide constructors • Additional methods • Change behavior of some supertype methods • Good programming practice allows only limited changes • Must provide new specification • Subtype implementations contain • Instance variables defined in supertype • Methods provided in supertype • Except private constructors
Defining Hierarchies • Supertypes come in three flavors • Classes (concrete classes): • All methods implemented • Abstract classes • Some methods implemented, some not • Some fields • No objects of an abstract class • Interfaces • No methods implemented • Why have these? • ActionListener example
Defining Hierarchies • Methods • Normal vs. final methods • Final methods cannot be overridden • Abstract methods • Methods with no implementations • These distinctions interesting only to implementors • Not to users!!! • Representations for subtypes include instance variables for • Supertype • and itself • Subtype can access supertype fields (instance variables) only if declared as protected • But protected variables are also package visible • Better if subclass only accesses superclass through public interface. Gives full modularity.
A Simple Example public class IntSet { //OVERVIEW: IntSets are mutable , unbounded sets of //integers. A typical IntSet is {x1, ... , xn} //constructors public IntSet() //EFFETCS: Initializes this to be empty. //methods public void insert (int x) //MODIFIES: this //EFFETCS: Adds x to the elements of this. public void remove (int x) //MODIFIES: this //EFFECTS: Removes x from this. public boolean inIn (int x) //EFFECTS: If x is in this returns true else //returns false. Continued next page
A Simple Example public int size () //EFFETCS: Returns the cardinality of this. public boolean subset (IntSet s) //EFFECTS: Returns true if this is a subset of s //else returns false. }
A Simple Example public class IntSet { private ArrayList<int> els; // the elements public IntSet () { els = new ArrayList<int> (); } private int getIndex (Integer x) { ... } private boolean isIn (int x) { return getIndex(new Integer(x)) >= 0; } public boolean subset (IntSet s) { if (s == null) return false; for (int i = 0; i < els.size(); i++) if (!s.is In(((Integer) els.get(i)).intValue())) return false; return true; } // implementations of other methods go here } • Observe • No protected methods • Concrete class: All methods implemented
public class MaxIntSet extends IntSet public class MaxIntSet extends IntSet { //OVERVIEW: MaxIntSet is a subtype of IntSet with an //additional method, max, to determine the maximum //element of the set. //constructors public MaxIntSet () //EFFECTS: Makes this to be empty MaxIntSet. //methods public int max () throws EmptyException //EFFECTS: If this is empty throws EmptyException // else returns the largest element of this. } • Only new methods need to be specified • New field: private int biggest; //the max element (if set is not empty)
MaxIntSet Constructor public MaxIntSet () { } automatically calls public MaxIntSet () { super() }; • Subtype constructor must call supertype constructor • Otherwise, supertype constructor with no arguments is called automatically
MaxIntSet Implementations public class MaxIntSet extends IntSet { private int biggest; //the biggest element if set is not empty public MaxIntSet () { super(); } public void insert (int x) { if (size () == 0|| x > biggest) biggest = x; super.insert(x); } public void remove (int x) { super.remove(x); if (size() == 0 || x < biggest) return; Iterator g = elements(); biggest = ((Integer) g.next()).intValue(); while (g.hasNext() { int z = ((Integer) g.next()).intValue(); if (z > biggest) biggest = z; } } Continue next page
A Simple Example public int max () throws EmptyException { if (size() == 0) throw new EmptyException (“MaxIntSet.max); return biggest; } }
Abstract Classes • Abstract class: Partial implementation of a type • May have instance variables, constructors, implementation of some methods • Constructors initialize supertype’s portion of the implementation • Allows code reuse, reliability • Some methods left unimplemented • Called abstract methods public boolean subset (IntSet s) //inherited public boolean subset (SortedIntSet s) // extra
Abstract Classes public class SortedIntSet extends IntSet { //OVERVIEW: A sorted int set is an int set whose elements are //accessible in sorted order. //constructors: public sortedIntSet() //EFFECTS: Make this be an empty sorted set //methods: public Iterator elements() //EFFECTS: Returns a generator that will produce all //elements of this, each exactly once, in ascending order. //REQUIRES: this not be modified while the generator is in use. public int max() throws EmptyException //EFFECTS: If this is empty throws EmptyException else //returns the largest element of this. public boolean subset (SortedIntSet s) } • has two subset methods public boolean subset (IntSet s) //inherited, no spec public boolean subset (SortedIntSet s) // extra, for // better performance
Abstract Classes • If subtype wants to use its own rep and not use the supertype’s, there’s no way to do so • In that case, make supertype abstract • No rep, therefore no objects of that type • No way for users to call constructor of abstract supertype
Abstract Classes public abstract class IntSet { protected int sz; // the size //constructors public IntSet () { sz = 0; } //abstract methods public abstract void insert (int x); public abstract void remove (int x); public abstract Iterator elements (); public abstract boolean reOk (); Continued next page
Abstract Classes //methods public boolean isIn (int x) { Iterator g = elements (); Integer z = new Integer(x); while (g.hasnext()) if (g.next().equals(z)) return true); return false; } public int size () { return sz; } // implementations of subset and toString go here publıc boolean subset (IntSet otherSet) } • size() could have been implemented using the elements() iterator • But would be inefficient • All subtypes need efficient size() implementation • Provide field sz and size() implementation • Allow subtypes access to sz
Interfaces • Interfaces • Define a type • Provide no implementation • Useful for providing multiple supertypes • Can implement many interfaces • But can extend only one class public class SortedIntSet extends ıntSet implements sortedCollection { ... }
Interfaces public interface Iterator { public boolean hasNext (); //EFFECTS: Returns true if there are more items to //produce else returns false. public Object next () throws NoSuchElementException; //MODIFIES: this //EFFECTS: If there are no more items to produce, //throw NoSuchElementException. Otherwise retuns //the next item and changes the state of this to //reflect the return. }
Multiple Implementations • Different implementations of a type • Some implementations more efficient for a subset of objects • E.g. Sparse vs. dense polynomials • Implementation subclasses invisible to users • Only referred to when creating new objects Poly p1 = new DensePoly(); Poly p2 = new SparsePoly(); • After some manipulation, p1 may refer to a SparsePoly and p2 may refer to a DensePoly
Multiple Implementations Example: Lists public abstract class IntList { //OVERVIEW: IntLists are immutable lists of Objects. A //typical IntList is a sequence [x1,..., xn]. //methods public abstract Object first () throws EmptyException; //EFFECTS: If this is empty throws EmptyException //else returns the first element of this. public abstract Intlist rest () throws EmptyException; //EFFECTS: If this is empty throws EmptyException //else returns the list containing all but the //first element of this, in the original order. public abstract Iterator elements (); //EFFECTS: Returns a generator that will produce //the elements of this, each exactly once, in the //order in this. Continue next page
Lists public abstract IntList addEl (Object x); public abstract int size (); //EFFECTS: Returns a count of the number of //elements of this. public abstract boolean repOk (); public String toString () public boolean equals (IntList o); }
List Implementation as Abstract Class public abstract class IntList { //OVERVIEW: Intlists are immutable lists of objects. A typical IntList is a sequence [x1, ..., xn] //abstract methods public abstract Object first () throws EmptyException; public abstract IntList rest () throws EmptyException; public abstract Iterator elements (); public abstract IntList addEl (Object x); public abstract int size (); //methods public String toString () { ... } Continue next page
List Implementation as Abstract Class public boolean equals (Object o) { try { return equals ((IntList) o); } catch (ClassCastException e) { return false; } } public boolean equals (IntList o) { //compare elements using elements iterator } }
Implementation 1: Empty List public class EmptyIntList extends IntList { public EmptyList () { }; public Object first () throws EmptyException { throw new EmptyException(“EmptyIntList.first”); } public IntList addEl (Object x) { return new FullIntList(x); } // not independent of // other implementation public boolean repOk () { return true); } public StringtoString () { return“IntList: []”; } public boolean equals (Object x) { return (x instanceof EmptyIntList); } //implementations of rest ans size go here public Iterator elements () { retun new EmptyGen(); } Continue next page
Implementation 1: Empty List static private class EmptyGen implements Iterator { EmptyGen () { } public boolean hasNext () { return false; } public Object next() throw NoSuchElementException { throw new NoSuchElementException(“IntList.elements”); } } //end EmptyGen } Continue next page
Implementation 2: FullIntList Public class FullIntList extends IntList { private int sz; private Object val; private IntList next; public FullIntList (Object x) { sz = 1; val = x; next = new EmptyIntList(); } // not independent of other implementation public Object first () { return val; } public Object rest () { return next; } public IntList addEl (Object x) { FullIntList n = new FullIntList(x); n.next = this; n.sz = this.sz + 1; return n; } // implementations of elements, size, repOk go here }
Example: Polynomial Superclass public abstract class Poly { protected int deg; //the degree //constructor protected Poly (int n) { deg = n; } //abstract methods coeff, repOk, add, mul, minus, terms //methods public int degree () { return deg; } public boolean equals (Object o) { try { return equals((Poly) o); } catch (ClassCastException e) { return false; } } Continue next page
Polynomials public boolean equals (Poly p) { if (p == null || deg != p.deg) return false; Iterator tg = terms(); Iterator pg = p.terms(); while (tg.hasNext()) { int tx = ((Integer) tg.next()).intValue(); int px = ((Integer) pg.next()).intValue(); if (tx != px || coeff(tx) != p.coeff(px) return false); } return true; } public sub (Poly p) { return add(p.minus()); } public String toString () { ... } }
Implementation 1: DensePoly private class DensePoly extends Poly { private int[] trms; //coefficients up to degree private DensePoly () { super(0); trms = new int[1]; } public DensePoly (int c, int n) throws NegExpExceptio { ... } private Densepoly (int n) { super(n); trms = new int[n+1]; } //implementation of coeff, add, mul, minus, terms and repOk go here public Poly add (Poly q) throws NullPointerException { if (q instanceof SparsePoly) return q.add(p); DensePoly la, sm; Continue next page
if (deg > q.deg) { la = this; sm = (DensePoly) q; } else { la = (DensePoly) q; sm = this; } int newdeg = la.deg; //new degree is the larger //degree if (sm.deg == la.deg) //unless there are trailing //zeros for (int k = sm.deg; k > 0; k--) if (sm.trms[k] + la.trms[k] != 0) break; else newdeg--; DensePoly r = new DensePoly(newdeg); //get a new //densePoly int i; for (i = 0; , i <= sm.deg && i <= newdeg; i++) r.rtms[i] = sm.trms[i] + la.trms[i]; for (int j = i; j <= newdeg; j++) r.trms[j] = la.trms[j]; return r; } }
How to enable users to ignore different implementations? • Make new “factory” class public class polyProcs { public static Poly makePoly () //EFFECTS: Returns the zero Poly. return new DensePoly() public static Poly makePoly (int c, int n) throws NegExpException //EFFECTS: If n < 0 throws NegExpException //else returns the monomial cxn. return new SparsePoly(c comma n) }