Interfaces

Interfaces & • What is an interface? Informally, it is a specification subtyping of how an agent interacts with the outside world

• Java has a construct called interface which is Lecture 4 used formally for this purpose – an interface describes how a class interacts with its clients CS 2112 – Spring 2014 – method names, argument/return types, fields

2

Java interface Notes

interface IPuzzle { • name of interface: void scramble(); IPuzzle int tile(int r, int c); • An interface is not a class! boolean move(char ); • a class implements – cannot be instantiated } this interface by – incomplete specification implementing class IntPuzzle implements IPuzzle { public instance public void scramble() {...} methods as • class header must assert implements I for Java to public int tile(int r, int c) {...} specified in the recognize that the class implements interface I public boolean move(char d) {...} } interface • the class may • A class may implement several interfaces: implement other class X implements IPuzzle, IPod {...} methods

3 4 Why an interface construct? Why an interface construct?

• good software engineering • Lots of examples in Java – specify and enforce boundaries between different parts of a team project Map h • can use interface as a type = new HashMap(); – allows more generic code List t = new ArrayList(); – reduces code duplication Set s = new HashSet();

5 6

Example of code duplication class Client{ IntPuzzle p1 = new IntPuzzle(); ArrayPuzzle p2 = new ArrayPuzzle(); • Suppose we have two implementations of puzzles: ...display(p1)...display(p2)... – class IntPuzzle uses an int to hold state public static void display(IntPuzzle p){ – class ArrayPuzzle uses an array to hold state for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++) Code duplicated System.out.println(p.tile(r,c)); because • Say the client wants to use both implementations } IntPuzzle – perhaps for benchmarking both implementations to pick the and best one public static void display(ArrayPuzzle p){ ArrayPuzzle – client code has a display method to print out puzzles for (int r = 0; r < 3; r++) are different for (int c = 0; c < 3; c++) System.out.println(p.tile(r,c)); • What would the method look like? } display }

7 8 One Solution ― Abstract Classes

abstract class Puzzle { Observation abstract int tile(int r, int c); ... } • Two display methods are needed because class IntPuzzle extends Puzzle { IntPuzzle and ArrayPuzzle are different types, Puzzle public int tile(int r, int c) {...} code ... and parameter p must be one or the other } class ArrayPuzzle extends Puzzle { public int tile(int r, int c) {...} • but the code inside the two methods is identical! ... } – code relies only on the assumption that the object p has an instance method tile(int,int) public static void display(Puzzle p){ • Is there a way to avoid this code duplication? Client for (int r = 0; r < 3; r++) code for (int c = 0; c < 3; c++) System.out.println(p.tile(r,c)); }}

9 10

Another Solution ― Interfaces IPuzzle interface IPuzzle { int tile(int r, int c); ... } IntPuzzle ArrayPuzzle class IntPuzzle implements IPuzzle { Puzzle public int tile(int r, int c) {...} code ... } • interface names can be used in type declarations class ArrayPuzzle implements IPuzzle { – IPuzzle p1, p2; public int tile(int r, int c) {...} ... } • a class that implements the interface is a subtype of the interface type public static void display(IPuzzle p){ – IntPuzzle and ArrayPuzzle are subtypes of IPuzzle Client for (int r = 0; r < 3; r++) – IPuzzle is a supertype of IntPuzzle and ArrayPuzzle code for (int c = 0; c < 3; c++) System.out.println(p.tile(r,c)); }}

11 12 Extending a Class vs Interfaces IPuzzle IPod IRon Implementing an Interface

• A class can Classes AClass BClass – implement many interfaces, but – extend only one class • Unlike classes, types do not form a tree! • To share code between two classes – a class may implement several interfaces – put shared code in a common superclass – an interface may be implemented by several classes – interfaces cannot contain code

13 14

Static vs Dynamic Types Example

int i = 3, j = 4; • Every variable (more generally, every expression that denotes some kind of data) has a static* or compile- Integer x = new Integer(i+3*j-1); time .out.println(x.toString()); – derived from declarations – you can see it – known at compile time, without running the program • static type of the variables i,j and the expression i – does not change +3*j-1 is int • static type of the variable x and the expression • Every object has a dynamic or runtime type new Integer(i+3*j-1) is Integer – obtained when the object is created using new • static type of the expression x.toString() is – not known at compile time – you can’t see it String (because toString() is declared in the class Integer to have return type String) * Warning! No relation to Java keyword static • dynamic type of the object created by the execution of is 15 new Integer(i+3*j-1) Integer 16 Reference vs Primitive Types Why Both int and Integer?

x: • Reference types • Some data structures work only with reference types – classes, interfaces, arrays ( ) (Integer) Hashtable, Vector, Stack, ... – E.g.: Integer int value: 13 String toString() ... • Primitive types are more efficient for (int i = 0; i < n; i++) {...} • Primitive types – int, long, short, byte, boolean, char, float, double

x: 13

17 18

Upcasting Upcasting and Downcasting • Example of upcasting: • Applies to reference types only • Used to assign the value of an expression of one Object x = new Integer(13); (static) type to a variable of another (static) type – static type of expression on rhs is Integer – upcasting: subtype → supertype – static type of variable x on lhs is Object – downcasting: supertype → subtype – Integer is a subtype of Object, so this is an upcast • A crucial invariant: • static type of expression on rhs must be a subtype of If during execution, an expression E is ever evaluated static type of variable on lhs – compiler checks this and its value is an object O, then the dynamic type of O is a subtype of the static type of E. • upcasting is always type correct – preserves the invariant automatically

19 20 Downcasting Is the Runtime Check Necessary?

• Example of downcasting: Yes, because dynamic type of object may not be known at compile time Integer x = (Integer)y;

– static type of y is Object (say) void bar() { – static type of x is Integer foo(new Integer(13)); } – static type of expression (Integer)y is Integer String(“x”) – Integer is a subtype of Object, so this is a downcast void foo(Object y) { • In any downcast, dynamic type of object must be a int z = ((Integer)y).intValue(); ... subtype of static type of cast expression } • runtime check, ClassCastException if failure • needed to maintain invariant (and only time it is needed) 21 22

Upcasting with Interfaces Why Upcasting?

• Java allows up-casting: IPuzzle p1 = new ArrayPuzzle(); • Subtyping and upcasting can be used to avoid code IPuzzle p2 = new IntPuzzle(); duplication • Puzzle example: you and client agree on interface • Static types of right-hand side expressions are IPuzzle ArrayPuzzle and IntPuzzle, resp. interface IPuzzle { void scramble(); • Static type of left-hand side variables is IPuzzle int tile(int r, int c); boolean move(char d); • Rhs static types are subtypes of lhs static type, so } this is ok

23 24 Solution Method Dispatch interface IPuzzle { int tile(int r, int c); public static void display(IPuzzle p) { ... for (int row = 0; row < 3; row++) } for (int col = 0; col < 3; col++) class IntPuzzle implements IPuzzle { System.out.println(p.tile(row,col)); Puzzle public int tile(int r, int c) {...} } code ... } class ArrayPuzzle implements IPuzzle { public int tile(int r, int c) {...} • Which tile method is invoked? ... } – depends on dynamic type of object p (IntPuzzle or ArrayPuzzle)

public static void display(IPuzzle p){ – we don't know what it is, but whatever it is, we Client for (int r = 0; r < 3; r++) know it has a tile method (since any class that code for (int c = 0; c < 3; c++) System.out.println(p.tile(r,c)); implements IPuzzle must have a tile method) }}

25 26

Method Dispatch Note on Casting public static void display(IPuzzle p) { for (int row = 0; row < 3; row++) for (int col = 0; col < 3; col++) • Up- and downcasting merely allow the System.out.println(p.tile(row,col)); } object to be viewed at compile time as a different static type • Compile-time check: does the static type of p • Important: when you do a cast, either up (namely IPuzzle) have a tile method with or down, nothing changes the right type signature? If not error → – not the dynamic type of the object • Runtime: go to object that is the value of , p – not the static type of the expression find its dynamic type, look up its tile method • The compile-time check guarantees that an appropriate tile method exists 27 28 Another Use of Upcasting Java instanceof Heterogeneous Data Structures • Example: if (p instanceof IntPuzzle) {...} • Example: IPuzzle[] pzls = new IPuzzle[9]; • true if dynamic type of p is a subtype of pzls[0] = new IntPuzzle(); IntPuzzle pzls[1] = new ArrayPuzzle(); • expression pzls[i] is of type IPuzzle • usually used to check if a downcast will succeed • objects created on right hand sides are of subtypes of IPuzzle

29 30

Example Avoid Useless Downcasting

• suppose twist is a method implemented void moveAll(IPuzzle[] pzls) { only in IntPuzzle for (int i = 0; i < pzls.length; i++) { if (pzls[i] instanceof IntPuzzle) void twist(IPuzzle[] pzls) { bad ((IntPuzzle)pzls[i]).move("N"); else ((ArrayPuzzle)pzls[i]).move("N"); for (int i = 0; i < pzls.length; i++) { }} if (pzls[i] instanceof IntPuzzle) { IntPuzzle p = (IntPuzzle)pzls[i]; p.twist(); } void moveAll(IPuzzle[] pzls) { } for (int i = 0; i < pzls.length; i++) } good pzls[i].move("N"); }

31 32 Coercions Subinterfaces • Sometimes Java will let you use a type as if it were another type but does an • Suppose you want to extend the interface to implicit coercion/conversion to the target include more methods type. – IPuzzle: scramble, move, tile • Looks like subtyping, but isn’t. – ImprovedPuzzle: scramble, move, tile, samLoyd int i; float f = i; • Two approaches – may lose information! – start from scratch and write an interface – extend the interface Object o = i; // = Integer.valueOf(i); IPuzzle – side effect: creates a new object 33 34

interface IPuzzle { void scramble(); A D int tile(int r, int c); boolean move(char d); } B E F interface ImprovedPuzzle extends IPuzzle { C void samLoyd(); } G I • IPuzzle is a superinterface of ImprovedPuzzle Interfaces Classes • ImprovedPuzzle is a subinterface of IPuzzle • ImprovedPuzzle is a subtype of IPuzzle • An interface can extend multiple superinterfaces interface C extends A,B {...} • A class that implements an interface must implement all class F extends D implements A {...} methods declared in all superinterfaces class E extends D implements A,B {...}

35 36 Factory methods Conclusion • Factory method: method to create an object • Idea: clients create objects with factory • Interfaces have two main uses methods, not constructors ! software engineering: good fences make good – clients do not explicitly select implementation neighbors – implementing class can even be hidden in its ! subtyping package (non-public) • Subtyping is a central idea in modern public static Puzzle createPuzzle(int size) { programming languages ! inheritance and interfaces are two methods for ! return new APuzzle(...); creating subtype relationships }

37 38