with Polymorphism and Lambda Expressions Interfaces with Polymorphism and Lambda Expressions
Outcomes Recognize, write, and implement interfaces Make a class sortable by implementing the Comparable<> interface Add different ways of sorting by implementing the Comparator<> interface Understand the significance of a SAM Single Abstract Method interface
Review of Inheritance One class a specialized version of another GridPane is a specialized Pane StackPane is a specialized Pane specialized version called subclass less specialized version called superclass Subclass gets all public superclass methods Subclass can stand in for superclass polymorphism
Review of Inheritance Use extends keyword Use super(…) in constructor public class Student extends Person Use super(…) in constructor public Student(String name) { super(name); // calls Person constructor Use @Override to change methods and super. to access inherited version of method @Override public String toString() { return super.toString() + " (" + A_NUM + ")"; }
Inheritance Hierarchies Organize classes by specialization MenuBar TextInputControl TextField Control Label PasswordField Labelled ButtonBase Arrows point from subclass to superclass Button CheckBox RadioButton ToggleButton
Single Inheritance Java allows only single inheritance can only extend one class public class StudentEmployee extends Student, Employee Because of “diamond problemˮ say Student & Employee both define toString Student name + A-number Employee name + SIN which version does StudentEmployee use? "Sam (A00000000)" or "Sam (000-000-000)"
The Object Class Superclass to every Java class no extends keyword extends Object NOTE: int, double, boolean, char are NOT classes Important methods from Object: toString() – translate to String equals(Object) – check for same content each of those needs to be overridden to be useful hashCode() – more about that in 2nd year CS
Abstract Class Class with missing method definitions abstract keyword for class and missing methods public abstract class Application { public abstract void start(Stage s); Cannot be instantiated (no new Application) Subclasses must define abstract methods @Override public void start(Stage s) { … } (or be abstract themselves)
Purpose of Abstract Classes Provide most of what programmers need Application provides launch method… …calls object methods when objects clicked But not everything because programmers want specialized versions Programmers fill in only missing bits Application needs to be told window contents .: programmer provides start(Stage) definition
Abstraction in JavaFX Application is abstract EventHandler is abstract our application extends Application abstract method start says what goes in the window/Stage EventHandler is abstract Button has an EventHandler onAction abstract method handle says what happens when button is clicked
Clicking a Button Button done = new Button("Done"); done.setOnAction((ActionEvent e) Platform.exit()); done Done Done & text: "Done" onAction: … ActionEvent e = new ActionEvent(…); e.getSource().getOnAction().handle(e); & e Button object & public void handle(ActionEvent e) { Platform.exit(); } source: … & EventHandler object ActionEvent object
Event Handlers Buttons have onAction field onAction object has a handle method onAction.handle called when button clicked Application class takes care of making that happen argument gives more information about the click setOnAction method sets onAction object expects to be given an EventHandler object handle is abstract method in EventHandler
EventHandler Methods handle is the only method in EventHandler its only job is to handle an event it only needs the handle method and it has no idea what that method does EventHandler has no method definitions not even a constructor so nothing to inherit so no diamond problem so…
Java Interfaces Java allows only single inheritance because of diamond problem – inheriting two versions of one method No diamond problem if all methods abstract so have a way of saying all methods abstract public interface Measurable says all methods in Measurable are abstract Measurable is called an interface (not a class)
Java Interfaces Just list the methods in the interface don’t even need to say they’re abstract public interface Measurable { public double getArea(); public double getPerimeter(); } import java.awt.Color; public interface Colourable { public Color getColor(); public void setColour(Color c);
extends versus implements For regular inheritance use extends public class Student extends Person Student inherits every public Person method For interfaces, use implements public class Circle implements Measurable Circle defines every Measurable method can implement multiple interfaces public class ColourCircle implements Measurable, Colourable
Implementing an Interface If you say you implement an interface… public class Circle implements Measurable …you must define all its methods @Override public double getArea() { return Math.PI * Math.pow(radius, 2); } @Override public double getPerimeter() { return 2 * Math.PI * radius;
Why Use Interfaces? We can say what needs doing without saying how it needs to be done because we mostly don’t care how it’s done (e.g.) we need an object to handle an event this class says it can be used to handle an event so use it! don’t get stuck with one class make an interface & let anyone implement it use new & better classes as they come along (it’s much easier to add new things)
Interface Tell Java that group of actions goes together name the group of actions say what the actions are do not say how to do them different kinds of things may do them different ways public interface Measurable { public double getArea(); public double getPerimeter(); } See Measurable.java
Using an Interface Tell method to expect a Measurable object can use any Measurable method for that object getArea or getPerimeter public double roundness(Measurable m) { return 4 * Math.PI * m.getArea() / Math.pow(m.getPerimeter(), 2); } cannot use any other methods! (*) we don’t know what other methods it might have (*) not exactly true, but pretty close! See MeasuringStuff.java
Using Measurable Objects Suppose Circle is Measurable Circle c = new Circle(10.0); System.out.println(“Roundness of c is ” + roundness(c)); c has getArea and getPerimeter methods… because Circles are Measurables …so method works just fine similarly for Rectangles Rectangle r = new Rectangle(10.0, 20.0); System.out.println(“Roundness of r is ” + roundness(r)); Roundness of c is 1.0 Roundness of r is 0.6981317007977318
Exercise Declare an interface named Playable that has the following methods: void play() void play(int numTimes) double playLength()
Making Classes Measurable Need to know that a class is Measurable it’s not enuf to just have the methods need to tell Java that we have the methods Done in the class declaration an implements clause (compare: throws clause) public class Circle implements Measurable { … } public class Rectangle implements Measurable { … } tells Java they have getArea & getPerimeter don’t lie! Java will catch you out
The Circle Implementation public class Circle implements Measurable { private double radius; public Circle(double r) { radius = r; } public double getRadius() { return radius; } public double getCircumference() { return 2 * Math.PI * radius; } public double getDiameter() { return 2 * radius; } public double getArea() { return Math.PI * Math.pow(radius, 2); } public double getPerimeter () { return getCircumference(); } } says it implements Measurable, then does has other methods, too – but that’s OK See Circle.java
The @Override Annotation NetBeans will notice methods that implement the Measurable interface will ask you to add @Override annotation Please do so! @Override public double getArea() { return Math.PI * Math.pow(radius, 2); } public double getPerimeter () { return getCircumference(); } NOTE: only on the methods named in Measurable public double getDiameter() { return 2 * radius; }
Overriding Interface Methods Interface says that class has the method does not say how the method works Class says how the method works @Override says that this method is the same as the one from the interface so computer can tell if you said it wrong The two must match exactly public double getArea(); // from Measurable public double getArea() { … } // from Circle Actually, the parameter names can be different….
The Rectangle Implementation public class Rectangle implements Measurable { private double length, width; public Rectangle(double l, double w) { length = l; width = w; } public double getLength() { return length; } public double getWidth() { return width; } @Override public double getArea() { return length * width; } public double getPerimeter () { return 2 * (length + width); } } says it implements Measurable, then does the implementations are different than for Circles See Rectangle.java
Exercise Write a Square class that implements the Measurable interface it has an edgeLength (double) area is edgeLength squared perimeter is four times edgeLength
Non-Interface Methods Class may have methods that are not part of the interface Rectangle: getHeight & getWidth Circle: getRadius & getCircumference Polymorphic parameters/variables cannot use those methods can only use interface methods
What’s OK? Methods you can ask for depend on the variable, not the object Circle c = new Circle(10); c.getPerimeter(); c.getArea(); c.getRadius(); c.getCircumference(); Rectangle r = new Rectangle(10, 20); r.getPerimeter(); r.getArea(); r.getHeight(); r.getWidth(); Measurable m = new Circle(10); m.getPerimeter(); m.getArea(); m.getRadius(); m.getCircumference();
Compile-Time Method Checking Try to make sure program won’t crash make it as safe as we can (no guarantees!) Asking a Rectangle for its radius would cause a crash Measurable could be a Rectangle Asking a Measurable for its radius could cause a crash
Run-Time Method Selection Anything we ask a Measurable to do... ...will be part of the interface because our compile-time checking made sure The Measurable object knows how to do it because of compile-time checking of class Object uses its own version of the method known as late (or dynamic) binding In C++, early (static) binding chooses a version of the method at compile time.
Variables & Types Measurable variable is polymorphic can hold a Circle or Rectangle object can assign from a different type variable Measurable m; Circle c = new Circle(10); Rectangle r = new Rectangle(10, 20); m = c; m = r; Compare storing an int variable into a double variable: int n = 5; double x = n;
Variables & Types Cannot go the other way around Measurable m = new Circle(10); Rectangle r; Circle c; r = m; c = m; doesn’t like either of those Compare storing a double variable into an int variable: double x = 5.0; int n = x;
Type Casting Can tell Java you want to do it anyway! tell Java to treat the Measurable as a Circle Measurable m = new Circle(10); Circle c; c = (Circle) m; will crash if object is wrong type Rectangle r; r = (Rectangle) m; Crash Contrast casting a double variable into an int variable: double x = 5.5; int n = (int)x;
Note: all lower-case letters! Checking the Type Can ask if an object is a given type hey, m, are you are Circle? if (m instanceof Circle) { Circle c = (Circle) m; double radius = c.getRadius(); Still can’t ask m to do non-Measurable stuff if (m instanceof Circle) System.out.print(m.getRadius()); Note: all lower-case letters!
Exercise Check a Measurable variable to see if it holds a Rectangle object. if it does, print out the Rectangle’s length and width
Interface Summary An interface is a data type variables can have that data type including (especially) parameters for methods such variables (methods) called polymorphic An interface lists public methods each implementing class implements them each class has its own implementation these classes are similar kinds of things Circles and Rectangles are similar kinds of things
Interfaces and Sorting Arrays.sort sorts arrays of some types Java must know how to sort them knows how to sort int, double, String, … doesn’t know how to sort user-defined classes Tell Java how to sort user-defined classes implement the Comparable<…> interface Arrays.sort expects its argument to be sortable objects must implement Comparable<…>
The Comparable<…> Interface Have to fill in the <…> what kind of thing it can be sorted with almost always itself public class Student implements Comparable<Student> Has exactly one method compareTo says how to compare to other @Override public int compareTo(Student other) how does this Student compare to other Student for Professor: public int compareTo(Professor other)
The compareTo Method compareTo returns an int value a.compareTo(b) < 0 a comes before b a.compareTo(b) > 0 a comes after b a.compareTo(b) == 0 doesn’t matter (equal) Similar to sorting numbers: a < b a comes before b a > b a comes after b a == b doesn’t matter (equal) For integer numbers, can just return a – b because a < b means a – b < 0.
Sorting Students Let’s sort Students by name name is a String String has a compareTo method so just return whatever it returns public int compareTo(Student other) { return this.name.compareTo(other.name); } “if you want to compare Students, compare their names.” See byName/Student.java
Sorting Students Add Students to list; sort list; print list Student[] ss = new new Student[]{ new Student(“Jake”), new Student(“Angie”), new Student(“Geety”)}; Arrays.sort(ss); System.out.println(Arrays.toString(ss)); [Angie (A00000002), Geety (A00000003), Jake (A00000001)] See byName/SortStudents.java
Sorting by Grade Sorting by numbers uses subtraction smallest to largest: this.number – other.number largest to smallest: other.number – this.number but result must be an int! public int compareTo(Student other) { return other.getAverage() – this.getAverage(); } sorts Students from highest to lowest grade See byGrade/Student.java and byGrade/SortStudents.java
Sorting by Double Values Need to change double to int (int) no good – changes 0.5 to 0 instead of 1 Use Math.signum to get sign of result then change to int public int compareTo(Line other) { double result = this.length – other.length; double sign = Math.signum(result); // -1.0, 0.0, or +1.0 return (int)sign; } sorts from shortest to longest See Line.java and SortLines.java
Exercise Write a compareTo method that sorts Students by A_NUMBER remember, it’s a String Write a compareTo method that sorts Lines from longest to shortest each Line has a length (double)
Sorting Strings String normally sort by lexicographic order Arrays.sort(words); all capital letters come before any small letters "Zulu" comes before "alpha" Often want alphabetical order "alpha" before "Zulu" Tell Arrays.sort we want a different order Arrays.sort(words, String.CASE_INSENSITIVE_ORDER);
String’s Case Insensitive Order String.CASE_INSENSITIVE_ORDER is a Comparator<String> object defines compare(String, String) method compare(a, b) < 0 a comes before b compare(a, b) > 0 a comes after b compare(a, b) == 0 doesn’t matter (equal) How different from Comparable<String>? compareTo(b) compare(a, b)
Two versions of Sort Arrays.sort(a) uses a[i].compareTo if (a[i].compareTo(a[i+1]) > 0) // need to swap used when objects have a natural order… …and we want that order Arrays.sort(a, cc) uses cc.compare if (cc.compare(a[i], a[i+1]) > 0) // need to swap used when object have no natural order… …or when we want a different order
Sorting in Many Ways Sometimes want to sort Students by grade (or by A-number) we’ll want (at least) these “ways to sort”: Student.BY_NAME Student.BY_GRADE Student.BY_ANUMBER each of these is a Comparator<Student> can compare Student objects sort can ask it if two Students are out of order
The Hardest Way The interface for “ways to sort” Need a class to implement the interface so we need three classes public class SortStudentsByName implements Comparator<Student> { … } public class SortStudentsByGrade implements Comparator<Student> { … } public class SortStudentsByANumber implements Comparator<Student> { … }
The Hardest Way The interface for “ways to sort” has exactly one method: int compare(_, _) very similar to compareTo method public class SortStudentsByName implements Comparator<Student> { public int compare(Student one, Student other) { return one.getName().compareTo(other.getName()); } NOTE: need getName, because this is not a Student
The Hardest Way Each comparator in Student is a Comparator each one is an object of the corresponding class public static final Comparator<Student> BY_NAME = new SortStudentsByName(); public static final Comparator<Student> BY_GRADE = new SortStudentsByGrade(); public static final Comparator<Student> BY_ANUMBER = new SortStudentsByANumber();
A Less Hard Way Don’t actually need to create new files don’t need SortStudentsByName.java &c. Use “anonymous” classes instead put Comparator definition inside Student.java public static final Comparator<Student> BY_NAME = new Comparator<Student>() { public int compare(Student one, Student other) { return one.getName().compareTo(other.getName()); } };
The Easy Way? Remember when we replaced anonymous classes with lambda expressions for buttons done.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { Platform.exit(); } }); became done.setOnAction((ActionEvent e) Platform.exit());
The Easy Way We can do the same for Comparable change anonymous class to lambda expression public static final Comparator<Student> BY_NAME = (Student one, Student other) -> { return one.getName().compareTo(other.getName()); }; public static final Comparator<Student> BY_GRADE = (Student one, Student other) -> { return other.getAverage() – one.getAverage();
Single Abstract Method Can use lambda expressions because Comparator has a single abstract method… compare …and it is given all the objects it needs given the two objects it needs to compare cc.compare(a[i], a[i+1]) compareTo only given one of those objects compareTo is addressed to the other one a[i].compareTo(a[i+1])
Lambda Expressions Arrays.sort 2nd argument is a Comparable Arrays.sort(words, x) words is String[] x is Comparator<String> x has compare(String, String) method lambda expression must say what that is (String a, String b) a.length() – b.Length() becomes @Override public int compare(String a, String b) { return a.length() – b.length(); }
Questions? Midterm test on Wednesday in lecture period, in lecture room up to end of week04 Inheritance and Polymorphism closed book no notes no calculators