Type Hierarchy Lecture 6: OOP, autumn 2003
The idea Many types have common behavior => type families share common behavior organized into a hierarchy Most common on the top - supertypes Most specific at the bottom - subtypes Many levels Typically depicted as upside-down tree subtype Substitutability => abstraction by specification Usage: Provide different implementations Extend class behavior supertype subtype
Inheritance in Java Inheritance mechanism Classes extend superclasses and implement interfaces Concrete classes - full implementation Abstract classes - partial abstract implementation, no objects Interfaces - only specification final methods - prevent inheritance abstract methods - no implementation Reimplementation <=> overriding Methods and attributes are inherited Visibility - private, public, protected The super( ) constructor and super keyword Only methods of the most specific class are executed
UML notation Person Teacher Student is-a Assistant Lecturer
Casting Upcasting/downcasting Widening for primitive types int x = 5; double y = x; Upcasting is implicit Student s = new Student(); Person p = s; Downcasting is explicit Student s = (Student) PersonSet.get(i); In java downcasting always checked at runtime if incorrect => throw ClassCastException
Overloading and overriding Overloading - abstract similar behavior in same class or subclass Reuse same name for similar behavior Needed for constructors Methods differ in parameters In Java no overloading on result type Overriding - replace functionality in subclasses Provide different implementations Methods have same signatures Special case of overloading Exist in most OO languages Main problem: How to determine the method to run? Compile-time: overloading resolution Run-time: dynamic binding
Overloading and overriding: example class X {} class Y extends X {} class A { public void f(x x) {} public void g(y y) {} } class B extends A { public void f(x x) {} public void g(y y) {} } class C extends B { public void f(y y) {} public void g(x x) {} } X Y A B C f(x) g(y) f(x) g(y) f(y) g(x) // varname = <apparent^actual> X xx = new X(); Y yy = new Y(); X xy = new Y(); C cc = new C(); B bb = new B(); B bc = new C(); cc.f(yy); // f in C cc.f(xx); // f in B cc.f(xy); // f in B bc.f(yy); // f in B bc.f(xx); // f in B bc.f(xy); // f in B cc.g(xx); // g in C cc.g(xy); // g in C bb.g(yy); // g in B bc.g(yy); // g in B
Overloaded method resolution in Java (1) Java uses dynamic binding, except final methods private methods Java tries to optimise dynamic binding with some pre-processing at compile time use apparent receiver and argument types to try to select a unique method aim: determine a unique method template to be used in the run-time dynamic binding search A method template: m: [ R, A, B, ] method receiver class parameter classes
Overloaded method resolution in Java (2) At compile-time, assemble a set of method templates whose receiver and parameters are type compatible with the call use apparent types of receiver and arguments start at receiver class and move upwards in hierarchy gather all templates that match, possibly widening receiver type or argument types Reduce this set to a unique most-specific template Most specific template => least type casts if any template in set has arguments or receiver that can be assigned to any other template in set, discard it repeat until one element left, or no more discards possible If unique most-specific template found, use it for run-time look-up If can t reduce to a unique match, report compile error
Dynamic binding (dispatching) Objects at run-time can be of subtypes Code can t execute methods directly Need to find actual implementation at run-time 1. At run-time, use actual type of receiver object to begin search for a method matching the template 2. Move upwards in hierarchy until find the first method matching template argument/parameter types must match exactly receiver run-time type must be subclass or same as template receiver type Use dispatch vectors
The substitution principle Enables reasoning using only supertype specification (abstraction again!) Any subtype object can be used in place of a supertype object without affecting using code Method/class design requirements: Signature rule - inherit all methods, compatible signature Methods rule -similar behavior Properties rule - preserve all superclass properties (e.g. invariants)
Substitution principle: the signature rule Guarantees type correctness for calls: correct for supertype => correct for subtype Enforced by Java compiler Subtypes have Same methods as in supertype Identical signatures Eventually less exceptions In principle can be relaxed - true suptyping Parameters of subtype methods - supertypes Results of subtype methods - subtypes
Substitution principle: the methods rule subtype's specification for any method must be at least as strong as its supertype's specification subtype method may weaken the precondition (require less) Less requires clauses Each clause is not stronger strengthen the postcondition (guarantee more) More clauses in postcondition Each clause can be stronger pre(super) => pre(sub) pre(super) & post(sub) => post(super) can not be checked by compiler
Substitution principle: the properties rule subtype must preserve all properties that can be proved about the supertype invariants guaranteed in supertype must be guaranteed by subtype subtypes may have stronger invariants - e.g sort order if only supertype methods/attributes considered, then any operation on subtype should result in same state as if supertype was modified