350 likes | 528 Views
EE2E1. JAVA Programming. Lecture 4 Interfaces. Contents. Interfaces – introduction Example – generic sorting Generic sorting – use of interfaces Properties of interfaces Example use of interfaces Callback functions. Interfaces - introduction.
E N D
EE2E1. JAVA Programming Lecture 4 Interfaces
Contents • Interfaces – introduction • Example – generic sorting • Generic sorting – use of interfaces • Properties of interfaces • Example use of interfaces • Callback functions
Interfaces - introduction • An interface is a construct consisting of unimplemented public methods (rather like abstract classes) • A class which implements an interface provides implementations of all of the methods declared in the interface • Interfaces are widely used in Java and enable multiple inheritance to be avoided
Example – generic sorting • Suppose we want write a sort program that is able to sort many kinds of objects • We can do this using inheritance and an abstract base class Sortable with method compareTo() • We derive what we want to sort from Sortable and polymorphism does the rest • For example, we can sort an array of students based on the IDNumber field • We need to provide an implementation of compareTo() in the class Student
public abstract class Sortable { public abstract int compareTo(Sortable b); }
compareTo(Sortable b)returns–1,0 or 1 depending on whether some chosen instance field f of a Sortable object is such that : • this.f<b.f • this.f==b.f • this.f>b.f
public class ArrayAlg { public static void shellSort(Sortable[] a) { int n = a.length; int incr = n / 2; while (incr >= 1) { for (int i = incr; i < n; i++) { Sortable temp = a[i]; int j = i; while (j >= incr && temp.compareTo(a[j - incr]) < 0) { a[j] = a[j - incr]; j -= incr; } a[j] = temp; } incr /= 2; } } }
public class Student extends Sortable { . . public intcompareTo(Sortable b) { Student s=(Student) b; if (idNnumber<s.idNumber) return –1; if (idNumber>s.idNumber) return 1; return 0; } private String name; private intidNumber; private String address; }
public class StudentSortTest { public static void main(String[] args) { Student[] s=new Student[3]; s[0]=new Student(“John Smith”, 3429, “21 Bristol Rd”); s[1]=new Student(“Alan Jones”, 5395, “30 Bournbrook Rd”); s[2]=new Student(“Peter Brown”, 1643, “20 Bristol Rd”); ArrayAlg.shellSort(s); // Sorts on id. number } }
Sortable Shape Square Generic sorting – use of interfaces • Suppose we wanted to sort objects of the class Square on the basis of length of side • Square is already derived from the abstract Shape class • Would need to also derive Square from Sortable for generic sorting
Java does not allow multiple inheritance (unlike C++) • The solution is to make the class Sortable an interface and then to make the class Square implement that interface • The interface contains the compareTo() method • This method is public by default • Any class implementing the interface must provide an implementation of compareTo() • An interface is similar to an abstract class but there are differences (see later)
public interface Sortable { public int compareTo(Sortable s); }
public class Square extends Shape implements Sortable { public Square(int x, int y, int s){super(x,y); side=s;} public float area() {return side*side;} public intcompareTo(Sortable s) { Square sq=(Square) s; if (side<sq.side) return –1; if (side>sq.side) return 1; return 0; } private int side; }
public class SquareTest { public static void main(String[] args) { Square[] s=new Square[3]; s[0]=new Square(10,0,0); s[1]=new Square(5,0,0); s[2]=new Square(15,0,0); ArrayAlg.shellSort(s); // Sorts on length of side } }
All descendants of a class would automatically implement any interfaces implemented by the class • For example, if Student implemented the Sortable interface, then so would UndergradStudent and PostGradStudent • UndergradStudent and PostGradStudent could then be sorted
We could also have used the interface Comparable defined in the standard package (Java.lang) • Provides a compareTo() method public interface Comparable { int compareTo(Object b); } • Java provides many interfaces in its standard packages
Properties of interfaces • Interfaces are similar to abstract classes in that they cannot be instantiated Sortable s = new Sortable(); // Error! Sortable is an interface • However, an interface can be the data type of an object reference Sortable s = new Square(…); // OK Square sq = new Square(…); if (s.compareTo(sq)>0) {…}
A class can only have a single parent, but it can have multiple interfaces • Multiple inheritance can lead to ambiguities in inheriting object instance fields whereas • Interfaces don’t have (non-static) instance fields – they are merely a set of methods that the object implementing the interface methods must define
public interface Drawable { intdraw(); } public class Square extends Shape implements Sortable, Drawable { public intcompareTo(Sortable s) {…} public int draw() {…} }
Example a Measurable interface • Suppose we have a DataSet class which computes simple statistics of numbers read from an input stream • For example, the average and maximum average Input stream DataSet maximum
public class DataSet { public DataSet() { sum=0.0; maximum=0.0; count=0; } public void add(double x) { sum+=x; if (count==0 || maximum<x) maximum=x; count++; } public double getAverage() { if (count==0) return 0; else return sum/count; } public double getMaximum() { return maximum; } private double sum, maximum; private int count; }
Clearly we would have to modify the DataSet class if we wanted to get the average of a set of bank account balances or to find the coin with the highest value amongst a set • DataSet is not re-useable as it stands • However, if all classes that DataSet objects operate on implement a Measurable interface, then the class becomes more flexible
public interface Measurable { double getMeasure(); } • Simple Measurable interface • Thus getMeasure() for BankAccount objects return the balance and for Coin objects returns the coin value
public class BankAccount implements Measurable { public BankAccount(double b) {balance=b;} public double getMeasure() { return balance; } private double balance; } public class Coin implements Measurable { public Coin(double c) {value=c;} public double getMeasure() { return value; } private double value; }
The Measurable interface expresses the commonality amongst objects • The fact that each measurable objects can return a value relating to its size • DataSet objects can then be used to analyse collections of objects of any class implementing this interface with minor modifications to the code
public class DataSet { public DataSet() { sum=0.0; count=0; } public void add(Measurable x) { sum+=x.getMeasure(); if (count==0 || maximum.getMeasure()<x.getMeasure()) maximum=x; count++; } public double getAverage() { if (count==0) return 0; else return sum/count; } public double getMaximum() { return maximum.getMeasure(); } private Measurable maximum; private double sum; private int count; }
DataSet d=new DataSet(); Coin c1=new Coin(10); Coin c2=new Coin(20); d.add(c1); d.add(c2); double maxCoin=d.getMaximum(); System.out.println("coin max= " + maxCoin); • We can now use these classes as follows:
Interfaces and callbacks • The DataSet class is useful as a re-usable class but is still limited • The Measurable interface can only be implemented by user defined classes • We can’t, for example, find the maximum of a set of Rectangle objects as Rectangle is a pre-defined class • We can only measure an object in one way. For example, in the case of BankAccount objects, we can only measure it in terms of the balance
The solution is to delegate the measuring to a separate class rather than being the responsibility of the objects we are measuring • We can create a separate Measurer interface and implement a measure() function in objects implementing this interface public interface Measurer { double measure(Object anObject); }
public DataSet { public DataSet(Measurer m) { measurer=m; } public void add(Object x) { sum=sum+measurer.measure(x); if (count==0 || measurer.measure(maximum)<measurer.measure(x)) maximum=x; count++; } …….. private Measurer measurer; } • We update the DataSet class as follows :
public class RectangleMeasurer implements Measurer { public double measure(Object anObject) { Rectangle r=(Rectangle) anObject; double area=r.getWidth()*r.getHeight(); return area; } }
A DataSetobject makes a callback to the measure() method of an objectimplementing the Measurer interface when it needs to measure an object (such as checking a bank balance) • This is in contrast to calling the getMeasure() method of an object implementing the Measurable interface • We are now free to design any kind of measures on an object of any class • For example, we can measure Rectangle objects by area • We require a RectangleMeasurer class which implements the Measurer interface
Measurer m=new RectangleMeasurer(); DataSet data=new DataSet(m); // Add rectangles to the data set data.add(new Rectangle(5,10,20,30)); data.add(new Rectangle(5,10,20,30)); // Get maximum double max=data.getMaximum(); • We can now use these classes as follows:
We have flexibility over our implementation of RectangleMeasurer so that any feature can be measured • Or even defining several measurer classes to measure different features
And finally • So far we have covered fundamental issues relating to object orientation including classes, inheritance and polymorphism and interfaces • In the next set of lectures we will cover more advanced features of java • Graphics and Swing • Files and streams • Multi-threading • Networks