Interfaces, Abstract Classes, and Polymorphism
What Is an Interface? An interface is the set of public methods in a class Java provides the syntax for specifying interfaces independently of their implementing classes
Example: An Interface for Circle import java.awt.Graphics; public interface CircleInterface { public void draw(Graphics g); public void move(int xDistance, int yDistance); public boolean equals(Object other); public String toString(); } An interface contains public method signatures and any necessary imports
Implementing an Interface import java.awt.*; public class Circle implements CircleInterface { // Variables and methods } import java.awt.*; public class Wheel extends Circle { // Variables and methods } Circle must implement draw, move, equals, and toString
The Client’s Perspective Circle c1 = new Circle(10,10,100,100,Color.blue); CircleInterface c2 = new Circle(); CircleInterface[] list = new CircleInterface[25]; Clients just look at the interface to see what they can do with circles An interface name can be substituted for the name of any implementing class
Implementing Several Interfaces import java.awt.*; import java.io.Serializable; public class Circle implements CircleInterface, Cloneable, Comparable, Serializable { // Variables and methods } Circle must implement draw, move, equals, and toString Circle must also implement clone and compareTo
Abstract and Concrete Classes An abstract class defines data and methods common to all subclasses, but is never instantiated A concrete class inherits some data and methods, defines others, and is instantiated
Example: Other Shapes RectangleTriangleCircle Wheel Rectangles and triangles are not really special types of circles, but have similar attributes and behavior
Define an AbstractShape Class RectangleTriangleCircle Wheel AbstractShape AbstractShape is never instantiated, but simply holds data and methods for its subclasses Each shape has a position, size, and color Most shapes move in a similar manner
An Interface for All Shapes import java.awt.Graphics; public interface Shape { public void draw(Graphics g); public void move(int xDistance, int yDistance); public boolean equals(Object other); public String toString(); }
Defining an Abstract Class abstract public class AbstractShape implements Shape{ protected Color color; protected int x, y, width, height; // Methods go here } abstract means that the class is not instantiated import java.awt.*; public class Circle extends AbstractShape { // Methods go here }
Polymorphism The move, draw, toString, and equals methods are polymorphic, in that they’re included in all classes but are implemented differently in some of them Try to exploit polymorphism to –reduce the amount of redundant code –reduce the conceptual overhead for clients
// In the AbstractShape class abstract public void draw(Graphics g); The keyword abstract requires all subclasses to implement a method An abstract method is implemented differently in each subclass Abstract Methods
// In the AbstractShape class abstract public double getArea(); When a Method Can’t Be Supported // In the Rectangle class public double getArea(){ return width * height; } // In the Line class public double getArea(){ throw new UnsupportedOperationException("Lines have no area"); return 0; }
// In the AbstractShape class public void move(int xDistance, int yDistance) x += xDistance; y += yDistance; } Overriding a Method // In the Triangle class public void move(int xDistance, int yDistance) super.move(xDistance, yDistance); // Code to adjust the other vertices goes here }
// In the AbstractShape class public final void setColor(Color c){ color = c; } The keyword final prohibits any subclass from overriding a method. Final Methods
Types of Polymorphism Behavioral – several classes implement one interface Structural – several classes implement one abstract class
The Advantages of Polymorphism // Create an array to hold up to 3 shapes of any type Shape[] shapes = new Shape[3]; // Add several shapes to the array shapes[0] = new Circle(50,50,100,100, Color.red); shapes[1] = new Rectangle(0,0,50,50, Color.blue); shapes[2] = new Triangle(0,0,100,100,60,30, Color.red); // Move them and draw them all for (int i = 0; i < shapes.length; i++){ shapes[i].move(50, 50); shapes[i].draw(g); }
Watch Out for Type Mismatches // Set the number of spokes of all wheels to 6 for (int i = 0; i < shapes.length; i++) shapes[i].setSpokes(6); Causes a compile-time error, because setSpokes is not included in the Shape interface and the array’s element type is Shape
Casting to the Rescue // Set the number of spokes of all wheels to 6 for (int i = 0; i < shapes.length; i++){ Wheel w = (Wheel)shapes[i]; w.setSpokes(6); } The compiler is now happy, but if shapes[i] is not actually a Wheel at run time, a ClassCastException will be thrown
Ask First // Set the number of spokes of all wheels to 6 for (int i = 0; i < shapes.length; i++){ if (shapes[i] instanceof Wheel){ Wheel w = (Wheel)shapes[i]; w.setSpokes(6); } Now both the compiler and the JVM will be happy
For Friday Exceptions and error handling Serialization (file transfers)