Interfaces
Interfaces • So far, we have talked about interfaces informally in the ordinary English sense of and the word. Sub-typing – “interface to a class tells the client how to obtain the functionality implemented in that class” • Java has a construct called interface which can be used formally for this purpose – and for doing some other really cool things…
Java interface Notes Class IntPuzzle implements IPuzzle{ • Interface itself cannot be instantiated. interface IPuzzle{ …… void scramble(); public void scramble(){ – incomplete specification int tile(int r, int c); …..} • It is not enough for a class to just have implementations public int tile(int r, int c){ boolean move(char d); of interface methods; class header must also assert } …..} public boolean move(char d){ “implements I” for Java to recognize that the class …..} implements interface I. } • A class may implement several interfaces. • Name of interface: IPuzzle – (eg) class X implements IPuzzle, IRaq { • A class can implement this interface by implementing public instance methods with the names and type ……} signatures specified in the interface. • The class may implement other methods.
1 Example of code duplication Why interface construct? • Suppose we have two implementations of puzzles: • One use of interfaces: software engineering – Class IntPuzzle uses an int to hold state – specifying and enforcing boundaries between – Class ArrayPuzzle uses an array to hold state different parts of a team project, as in Puzzle • Assume client wants to use both implementations in code example. – perhaps for benchmarking both implementations to pick • But interfaces can do much more. the best one? – Interfaces let you write more “generic” code – client code has a display method as always to print out puzzles that reduces code duplication. • What would the display method look like?
Class Client{ IntPuzzle p1 = new IntPuzzle(); Observation ArrayPuzzle p2 = new ArrayPuzzle(); ….display(p1)…display(p2)… • Two display methods are needed because types public static void display(IntPuzzle p){ IntPuzzle and ArrayPuzzle are different, and for (int r = 0; r < 3; r++) parameter p must have one type or the other. for (int c = 0;c<3;c++) { System.out.print(p.tile(r,c)); • Ironically, the code inside the two methods is Code duplicated System.out.print(‘ ‘); identical. because types }} – Code relies only on assumption that parameter p is passed IntPuzzle and public static void display(ArrayPuzzle p){ an object that has an instance method tile(int,int). ArrayPuzzle for (int r = 0; r < 3; r++) are different. • Is there a way to avoid this code duplication? for (int c = 0;c<3;c++) { System.out.print(p.tile(r,c)); – Use interfaces and sub-typing System.out.print(‘ ‘); }} }
2 Interfaces as types Note
IPuzzle Interfaces: IPuzzle IRan IRaq IntPuzzle ArrayPuzzle
Classes: AClass BClass • Name of an interface can be used as a variable type. – (eg) IPuzzle p1, p2; • Class that implements the interface is said to be a sub-type of • Since a class can implement several interfaces, it the interface type. may have many super-types. – IntPuzzle and ArrayPuzzle are sub-types of IPuzzle. • Interface is said to be a super-type of those classes. • An interface can be implemented by several – IPuzzle is a super-type of type IntPuzzle and ArrayPuzzle. classes, so it may have many sub-types.
Names, Objects and Types Paradox with interfaces as types • In programming languages, like in real life, • We cannot instantiate an interface I. we attribute type both to names (variables) – Interface is a partial specification. and to objects. • If we cannot create objects of type I, why bother • Example from real life: gender permitting interface names to be types? – Two types: Male and Female – (eg) IPuzzle p1,p2; – These types are assigned to people (objects): – Fine, but what would we ever assign to p1 and p2?!! • The President of Cornell is a Male. • To understand this, let us look at a real-life • The Provost of Cornell is a Female. analogy. – These types are also assigned to names: • Male George, Sam, Helmut, Bubba; • Female Rie, Naomi, Indira, Melanie;
3 Sub-typing in real life Unisex names Human
Male Female • Some names can refer to people of either gender: • Let us add a new type called Human. • Humans have certain functionalities: (eg): Sandy, Pat, Jackie – They walk upright. • How do we fit unisex names into our – They have juxtaposed thumbs. – They are intelligent…. classification? • Male and female are sub-types of type Human because they implement this functionality although in different • Here is an idea…. ways. • Like an interface, type Human cannot be instantiated directly: every human must be either a male or a female.
Sub-types and subsets
Human Back to names Male Female Male Female Human • Using these types, we can now give types to Sub-types Subsets unisex names as well: • Male George, Sam, Helmut, Bubba; • Sub-types and subsets are distinct concepts. • Female Rie, Naomi, Indira, Melanie; • Sub-types are characterized by some common • Human Jo, Sandy, Pat; functionality. – Sub-type female in our example is characterized by ability to give birth. • In this example, a mixture of males and females is a subset of type human, but it is not a sub-type.
4 Naming people Up-casting
• Simple picture without sub-typing: • Situation is a little more complex with unisex names (sub-typing). – Male objects get male names. – Female objects get female names. • Example: Sandy = new Female(); – Type of reference returned by RHS is Female. •Examples: – Type of LHS name is Human. //we created a new male object and named it George – Nevertheless, no type error because Female is sub-type George = new Male(); //type checks of Human. //give object named Sam the alias Bubba • Up-casting: type of RHS reference is sub-type of Bubba = Sam; //type checks type of LHS name. //give object named Bubba the alias Melanie • Up-casting is always type-correct. Melanie = Bubba;//type mismatch • Example: Sandy = Laura; • In last example, we do not need to know anything about – You do not need to know the object named Laura to who Bubba is to see that there is a type mismatch. determine that the assignment is type-correct.
Down-casting Resolution of paradox with • Is this type-correct? Bubba = Sandy; interfaces as types • Answer: depends. • Java allows up-casting: – Type of RHS name (reference) Sandy is Human which is super-type of LHS name – IPuzzle p1 = new ArrayPuzzle(); – Type of object named Sandy: either Male or Female – IPuzzle p2 = new IntPuzzle(); – Whether or not the assignment is legal depends not on the •Note: type of the RHS reference but on the type of the actual object. – Type of reference returned by right-hand side • Down-casting: Type of LHS name is sub-type of RHS expression of first statement is ArrayPuzzle. reference. – Type of variable on left-hand side is IPuzzle. • Down-casting may or may not be legal – Two types are different, but type of rhs reference is a – need to look at object to determine legality sub-type of type of the variable.
5 Your code Why up-casting?
Class IntPuzzle implements IPuzzle{ • Sub-typing and up-casting allow you to avoid …scramble()…tile()…move()…twist() code duplication in many situations. } • Puzzle example: you and client agree on interface Class ArrayPuzzle implements IPuzzle{ IPuzzle. ……scramble()...tile()…move()… } interface IPuzzle{ void scramble(); Class IntPuzzle implements a method called twist int tile(int r, int c); which is not a method of interface IPuzzle. boolean move(char d); }
Client Code Method execution
public static void display(IPuzzle p){ Class Client{ for (int r = 0; r < 3; r++) IntPuzzle p1 = new IntPuzzle(); for (int c = 0;c<3;c++) { ArrayPuzzle p2 = new ArrayPuzzle(); System.out.print(p.tile(r,c)); ….display(p1)…display(p2)… Up-casting: System.out.print(‘ ‘); Objects of type IntPuzzle }} public static void display(IPuzzle p){ and ArrayPuzzle are for (int r = 0; r < 3; r++) passed to parameter of • Subtle point: which tile method is invoked in code shown for (int c = 0;c<3;c++) { type IPuzzle. above? System.out.print(p.tile(r,c)); – tile method in IntPuzzle class?? System.out.print(‘ ‘); • What if object passed in is of type ArrayPuzzle? }} – tile method in ArrayPuzzle class?? } • What if object passed in is of type IntPuzzle? – tile method in IPuzzle interface?? • Huh?? • To understand this, let us look again at execution model.
6 Program area IntPuzzle: ..scramble..tile…move… ArrayPuzzle:..scramble..tile..move.. Resolving the name “p.tile”
Heap • Stack frame for invocation of display has storage for variables p,r,c. Stack IntPuzzle • Suppose method is passed an IntPuzzle object in parameter p as shown. c i: ArrayPuzzle r i: • Invocation “p.tile(r,c)” in body of display is p IPuzzle: scramble executed as discussed earlier: tile scramble – Look up method tile in object O referenced by p. move tile – Invoke that method passing it this (object O),r,c. move – In our example, therefore, we would invoke the tile method implemented in the IntPuzzle class.
Note on type-checking Think public static void display(IPuzzle p){ • Type of paramater p: IPuzzle for (int r = 0; r < 3; r++) – IPuzzle itself does not have a tile method! for (int c = 0;c<3;c++) { • Actual method that gets invoked is implemented System.out.print(p.tile(r,c)); sometimes in the ArrayPuzzle class and System.out.print(‘ ‘); sometimes in the IntPuzzle class! }}
• Dynamic method binding: • Compile-time check: does type of reference p (IPuzzle) – Name “p.tile” is not resolved to a single method. have a method called tile with the right type signature? If – In different invocations, name may be resolved to not, error. different methods. • Runtime: go into object referred to by p and look up its tile • Method display is sometimes said to be a method. polymorphic/generic method. • Remember: type of reference MUST have appropriate – Parameters are not restricted to be of a single type. method even though method that is invoked at runtime is in the class of the object.
7 Note on casting of references Other languages
• Dynamic method binding is a powerful • Think of reference as a pair
IntPuzzle p = new IntPuzzle(); IntPuzzle IPuzzle IPuzzle z = (IPuzzle)p; Another use of up-casting
• Sub-types and up-casting are useful for storing IntPuzzle Heap heterogeneous objects in data structures. •Example: Stack IntPuzzle IPuzzle[] AP = new IPuzzle[0..9]; AP[0] = new IntPuzzle(); z IPuzzle scramble AP[1] = new ArrayPuzzle(); p IntPuzzle tile • Note up-casting: move – names AP[0] etc. are of type IPuzzle – Objects created on right hand sides are of sub-types of IPuzzle.
8 Down-casting in Java instanceof • Java permits down-casting but casting is specified • Suppose we stick a bunch of ArrayPuzzle and IntPuzzle explicitly. objects into an IPuzzle array AP. • Suppose AP is passed to another method which walks public static void foo (IPuzzle p){ over the array and counts how many IntPuzzle objects if (p instanceof IntPuzzle) there are. IntPuzzle ip = (IntPuzzle)p; ….} • How does this method examine the type of the objects stored in array AP? • Compile-time: check that type of reference p is super-type of type of LHS name ip. – Making you write cast explicitly forces you to boolean b = AP[i] instanceof IntPuzzle; document down-casting. //b will be true if AP[i] refers to IntPuzzle object; false otherwise • Run-time: check that type of object referenced by //general syntax: reference instanceof className RHS is a sub-type of type of LHS name.
Down-casting in real life Note on down-casting
Human Canine Animal Animal a = new Female(); Male Female Human Human h = (Human)a; • Canine names Canine Spot, Rover; Female Male • George = (Male)Sandy; – Compile-time: is type of reference Sandy (Human) a super-type of type of George (Male)? Yes. • In down-casting, the types of the lhs variable, the – Run-time: is object referenced on RHS a sub-type of Male? • No: error - throw class cast exception. rhs reference, and the object the rhs reference • Yes: everything is cool. points to could all be different as in this example. • Spot = (Canine)Sandy; – Compile-time: is type of reference Sandy (Human) a super-type of type of Spot (Canine)? No. Compiler error.
9 Why down-casting? Example
void twister(IPuzzle[] AP) { • Sometimes you want to for (int I = 0; I Poor use of down-casting void mover(IPuzzle[] AP) { void mover(IPuzzle[] AP) { Super-interfaces for (int I = 0; I 10 Extending interfaces interface IPuzzle{ Super-interfaces void scramble(); int tile(int r, int c); boolean move(char d); • Interface can extend multiple super- } interface ImprovedPuzzle extends IPuzzle{ interfaces. void SamLoyd(); • Class that implements an interface must } implement all methods declared in super- •IPuzzle is a super-interface of ImprovedPuzzle interfaces. interface. •ImprovedPuzzle interface is a sub-interface of IPuzzle. •ImprovedPuzzle can be used as a type for variables like any other interface. •It is a sub-type of IPuzzle type. Type Hierarchy • Suppose class C implements a sub-interface Interfaces: IPuzzle IRan IRaq IB. There is no need to declare super- interfaces of IB in the “implements” clause of class C. ImprovedPuzzle • Rules for up-casting and down-casting references stay the same as before. Classes: AClass BClass class AClass implements ImprovedPuzzle, IRan { ……} //There is no need to specify explicitly that AClass implements //interface IPuzzle. 11 Editorial comments • Up-casting: super-type name on lhs of assignment – Example: Sandy = Laura; – Used in writing polymorphic methods and for declaring data • Interfaces have two main uses: structures that can hold heterogenous data – Software engineering: – Up-casting is always legal. • Good fences make good neighbors. – Sub-typing: • Down-casting: sub-type name on lhs of assignment • Type of interface is super-type of type of class implementing that – Explicit cast required in Java. interface. – Example: Laura = (Female) Sandy; • Use sub-types to write more generic, polymorphic code. – May or may not be legal: • Sub-typing is a central idea in programming • Compile-time check: Is type of lhs reference a sub-type of rhs languages. reference? (eg. Is Female a sub-type of Human?) – Inheritance gives another method for creating sub-types. – Runtime check inserted: may throw exception • Sub-typing is sometimes referred to informally as • Type of object on rhs may not be a sub-type of type of lhs reference. is-a relationship. Human Sandy = new Female(); – (eg) Every Female is-a Human. Male George = (Male) Sandy;//class cast exception – Less common than up-casting • Dynamic method binding – Method call r.m(..,..,..); – Remember that type of reference r may be different from type of object pointed to by r. – Compile-time check: does type of reference r have a method named m with appropriate parameter types? – Run-time: look inside object named by r and invoke method named m with the appropriate type signature. • Sub-typing and dynamic method binding permit you to write polymorphic/generic methods to avoid duplicating code for each type. 12