|
8: Abstract Classes, Polymorphism and Interfaces
What We Will Cover
Illuminations
^ top
8.1: Abstract Classes and Polymorphism
Learner Outcomes
At the end of the lesson the student will be able to:
- Code abstract classes
- Describe the elements of a polymorphic system
- Generate polymorphic behavior in Java programs
|
^ top
8.1.1: Abstract Classes and Methods
- When designing a program using inheritance, you often create a superclass that you do not want instantiated
- Instead, you only want subclasses of this superclass to be instantiated
- The superclass contains code common to all the subclasses but should not be instantiated
- For example:
Shape
- You cannot draw a generic shape -- what would it look like?
- Instead, you create subclasses that implement specific shapes
- Here is an example of an inheritance hierarchy for drawing various shapes
Inheritance Hierarchy

Creating Abstract Classes
- One solution to preventing a superclass from being instantiated is to make it abstract
- Abstract classes provide common code for all its subclasses
- A subclass inherits all variables and methods from the abstract class
- An abstract class often defines a set of operations for subclasses, providing a common interface for the subclasses
Coding an Abstract Class
- Any class can become abstract using the keyword
abstract
- Declaring a class
abstract means that you cannot instantiate an object of the class
- Instead, you must subclass the abstract superclass to make use of its operations
- The following example shows a class defined as abstract
Example Abstract Class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public abstract class Shape {
// regular instance variable declarations
private int x1, x2, y1, y2;
// regular constructor and method declarations
public Shape() { }
public Shape(int newX1, int newY1, int newX2,
int newY2) {
x1 = newX1;
x2 = newX2;
y1 = newY1;
y2 = newY2;
}
public int getX1() { return x1; }
public int getX2() { return x2; }
public int getY1() { return y1; }
public int getY2() { return y2; }
// Abstract method declaration
public abstract void draw();
}
|
Abstract Methods
^ top
8.1.2: Introduction to Polymorphism
Polymorphism Example
- Suppose you are designing a graphics package
- You have classes for several figures such as lines, rectangles and squares
- Each figure is an object of a different class
- In a well-designed program, all of these shapes would be subclasses of one superclass, call it
Shape

- The superclass has code common to all the subclasses
- For example, it might have variables for x and y coordinates to locate the object on the screen
- Also, it would have get and set methods for the variables
- In addition, the
Shape class has an abstract methods named draw() that is overridden in each subclass
- Each subclass only implements the code it needs, such as overriding the
draw() method to draw its shape on the screen
The Application Program
^ top
8.1.3: Implementing Polymorphism
- It turns out that this design works out well in Java
- Calling the correct drawing method of the subclass is done automatically
- Here is a simple implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
abstract class Shape {
private int x1, x2, y1, y2;
// regular constructor and method declarations
public Shape() { }
public Shape(int newX1, int newY1, int newX2,
int newY2) {
x1 = newX1;
x2 = newX2;
y1 = newY1;
y2 = newY2;
}
public int getX1() { return x1; }
public int getX2() { return x2; }
public int getY1() { return y1; }
public int getY2() { return y2; }
// Abstract method declaration
public abstract void draw();
}
class Line extends Shape {
public void draw() {
System.out.println("Drawing a Line.");
}
}
class Rectangle extends Shape {
public void draw() {
System.out.println("Drawing a Rectangle.");
}
}
class Square extends Rectangle {
public void draw() {
System.out.println("Drawing a Square.");
}
}
class Oval extends Shape {
public void draw() {
System.out.println("Drawing an Oval.");
}
}
public class DrawingApp {
private Shape shapes[] = {new Line(),
new Rectangle(), new Square(), new Oval()};
public static void main(String args[]) {
DrawingApp app = new DrawingApp();
app.drawShapes();
}
public void drawShapes() {
for (Shape s : shapes) {
s.draw();
}
}
}
|
- So why does this work?
- Answer: dynamic binding
Static vs. Dynamic Binding
- Binding: the process of associating a method definition with a method call.
- Static binding: done at compile time
- Dynamic binding: done at run-time
- Compilation binds memory locations to methods before running a program
- Binding done at compile time is called static, or early, binding
- In contrast, binding done at run time is called dynamic, or late, binding
- Java uses dynamic binding for all instance methods
- In contrast, static methods are bound at compile time (static binding)
- Polymorphism in Java relies on late binding and thus instance methods
^ top
8.1.4: Making Changes
- Let us suppose that our program is already written and in use
- Now a customer wants us to add a new shape like a triangle
- To make the change, we create a
Triangle class and add it to the program
- We want to make minimal changes and so have
Triangle subclass Shape
- Do we need to change
Shape to implement this new class?
Adding a Triangle
- Here is the code for our
Triangle class:
class Triangle extends Shape {
public void draw() {
System.out.println("Drawing a Triangle.");
}
}
- All need now is a way to add
Triangle objects to the shapes array
- For our simple application:
private Shape shapes[] = { new Line(),
new Rectangle(), new Square(),
new Oval(), new Triangle() };
- Note how easy it is to change a polymorphic program
- One of the chief advantages of polymorphism is extensibility
^ top
8.1.5: Summary
Check Yourself
- What is an abstract class?
- Why is an abstract class useful in programming?
- How do you declare a class to be abstract?
- What is an abstract method?
- What is the purpose of an abstract method?
- What is polymorphism?
- What determines which method is run in the following:
Shape s = new Square();
s.draw();
- The type of the object
- The type of the reference variable
- What is the advantage of a polymorphic system?
^ top
Exercise 8.1
Take two minutes to prepare an answer the following questions:
- What is the class hierarchy of the following
Polymorphism code?
- What will be the result of attempting to compile and run the following code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Polymorphism {
public static void main(String[] args) {
A ref1 = new C();
B ref2 = (B) ref1;
System.out.println(ref2.f());
}
}
class A { int f() { return 1; } }
class B extends A {
int f() { return 2; }
}
class C extends B {
int f() { return 3; }
}
|
^ top
8.2: Interfaces
Learner Outcomes
At the end of the lesson the student will be able to:
- Declare and Implement interfaces
- Use interfaces as arguments to methods
|
^ top
8.2.1: Introduction to Interfaces
Example Interface
Example Interface Implementation
^ top
8.2.2: Abstract Classes vs. Interfaces
- Abstract classes and interfaces have many similarities and differences
- Both abstract classes and interfaces allow you to define constants
- In addition, both abstract classes and interfaces allow you to declare abstract methods
- These similarities mean that interfaces can sometimes be used instead of an abstract class
Advantages of an Abstract Class
- An abstract class can have instance variables while an interface cannot
- An abstract class can define regular methods while interfaces can only declare abstract methods
- An abstract class can define static methods while an interface cannot
Advantages of an Interface
- A class can only inherit from one class but can directly implement many interfaces
- Any object that implements an interface can be used wherever the interface is accepted
When Will You Need Interfaces?
- You often need to implement interfaces in the Java API
- In particular, interfaces are used in coding graphical user interfaces
- You design interfaces most often when creating larger applications
^ top
8.2.3: Coding Custom Interfaces
- Declaring an interface is similar to declaring a class
- You use the keyword
interface instead of class
- General syntax:
public interface InterfaceName {
[public] [static] [final] dataType CONSTANT_NAME = value;
returnType methodName(parameterList);
}
- Where:
- InterfaceName: the name you make up for the interface
- dataType: the type of constant
- CONSTANT_NAME: the name you make up for the constant
- value: the value of the constant
- returnType: the type of value returned by the method, or
void for no return value
- methodName: the name you make up for the method
- parameterList: the types and names of the parameters
- The constant variables and abstract methods are optional
- For example:
public interface Drawable {
public static final int FILLED = 0;
public static final int UNFILLED = 1;
public void draw();
}
- Declares an abstract method named
draw()
- You cannot write the implementation of the method in the interface
- Instead, you write the implementation of the method in any class that
implements the interface
- All methods are
public and abstract by default
- Similarly, all constants are
public static final by default:
- Using the keywords
public static final is optional
- Though optional, they help to document the scope
- Note that interface methods cannot be declared
static
- Any interface method that is implemented becomes an instance method
Extending Interfaces
- You can derive new interfaces from an existing one just like classes can extend classes
- One difference is that an interface can extend multiple interfaces
- Syntax:
public interface InterfaceName
[extends SuperInterface1 [, SuperInterface2]...] { }
- Where:
- InterfaceName: the name you make up for the interface
- SuperInterfaceX: the name of the interface being extended
- For example, we could split our
Drawable interface into two superinterfaces and one subinterface
- The superinterfaces now contain the constants:
interface DrawingConstants {
public static final int FILLED = 0;
}
interface DrawingConstants2 {
public static final int UNFILLED = 1;
}
- The subinterface contains the method declaration:
interface Drawable
extends DrawingConstants, DrawingConstants2 {
public void draw();
}
- The new
Drawable has the same capabilities as the old Drawable
^ top
8.2.4: Implementing Interfaces
- Any class can choose to implement zero or more interfaces
- Syntax:
public class ClassName [extends SuperClass]
[implements Interface1 [, Interface2]...] { }
- Where:
- ClassName: the name you make up for the class
- SuperClass: the name of the parent class
- InterfaceX: the name of the interface being implemented
- Classes implementing an interface add the keyword
implements in the class header
- After the
implements keyword, code a comma-delimited list of interface names
- For example:
public class Map implements Drawable
- Class
Map must now implement the method draw()
- Note that you can refer to a constant declared in the interface without the interface name if you implement the interface
int filled = UNFILLED;
- A class that implements an interface must implement all methods of the interface:
public class Map implements Drawable {
int filled = UNFILLED;
public void draw() {
System.out.println("Drawing a Map.");
}
}
^ top
8.2.5: Interfaces as Arguments
Example Method with an Interface Argument
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
interface Drawable {
public void draw();
}
class Map implements Drawable {
public void draw() {
System.out.println("Drawing a Map.");
}
}
class Shape implements Drawable {
public void draw() {
System.out.println("Drawing a Shape.");
}
}
public class ShapeApp {
public static void main(String[] args) {
Map m = new Map();
Shape s = new Shape();
drawTwice(m);
drawTwice(s);
}
public static void drawTwice(Drawable d) {
d.draw();
d.draw();
}
}
|
- Since both the
Map and Shape class implements Drawable, they must implement the draw() method
- We can send either a
Map or a Shape to the drawTwice() method
- Creates a flexible polymorphic design that lets us easily add new classes into the system
^ top
8.2.6: Interfaces and Polymorphism
- You can implement polymorphism using interfaces rather than an abstract class
- It is also easy to mix both interfaces and abstract classes in one design
- Here is an example implementation
Example Polymorphic Design Using Interfaces and Abstract Classes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
interface Drawable {
void draw();
}
class Shape implements Drawable {
public void draw() {
System.out.println("Drawing a Shape.");
}
}
class Circle extends Shape {
public void draw() {
System.out.println("Drawing a Circle.");
}
}
class Rectangle extends Shape {
public void draw() {
System.out.println("Drawing a Rectangle.");
}
}
class Square extends Rectangle {
public void draw() {
System.out.println("Drawing a Square.");
}
}
class Map implements Drawable {
public void draw() {
System.out.println("Drawing a Map.");
}
}
public class Polymorph {
Shape[] s = { new Circle(), new Rectangle(),
new Square() }; //(1)
Drawable[] d = { new Shape(), new Rectangle(),
new Map() }; //(2)
public static void main(String args[]) {
Polymorph poly = new Polymorph();
poly.drawShapes();
poly.drawDrawables();
}
public void drawShapes() {
System.out.println("Draw shapes:");
for (int i = 0; i < s.length; i++) //(3)
s[i].draw();
}
public void drawDrawables() {
System.out.println("Draw drawables:");
for (int i = 0; i < d.length; i++) //(4)
d[i].draw();
}
}
|
- At (1),
shapes[] holds references to various Shape objects
- At (2),
drawables[] holds references to classes that implement Drawable interface
- Calling the
draw() method at (3) and (4) relies on polymorphism
- At runtime, dynamic lookup determines which
draw() method to use
- It is easy to add new classes to the
Shape or Drawable arrays
- There is no need to change any conditional logic
^ top
8.2.7: Summary
- An even more abstract "class" is an interface
- An interface can contain:
- Static constants
- Abstract methods
- For example:
public interface Drawable {
public static final int FILLED = 0;
public static final int UNFILLED = 1;
public void draw();
}
- The advantage of an interface is that classes can implement many interfaces
- Provides many of the advantages of multiple inheritance without the headaches
- All methods of an interface are
public and abstract by default
- Similarly, all constants are
public static final by default
- You can extend interfaces using the
extends keyword:
public interface InterfaceName
[extends SuperInterface1 [, SuperInterface2]...] { }
- Any class can choose to implement zero or more interfaces
- When it does, it must implement all the methods of the interface:
public class Map implements Drawable {
public void draw() {
System.out.println("Drawing a Map.");
}
}
- A method that accepts an interface as an argument can accept any object that implements that interface:
public static void drawTwice(Drawable d) {
d.draw();
d.draw();
}
- You can use interfaces to implement polymorphic systems as well
^ top
Exercise 8.2
Take one minute to prepare an answer the following question:
- Which of the following statements are true about interfaces:
- Members of an interface are never static
- Members of an interface can always be defined static
- Interfaces can implement variables but not methods
- Interfaces can extend any number of other interfaces
- Constants in an interface must be declared public or compilation will fail
^ top
Wrap Up
Due Next: Midterm Exam (4/7/10)
A7-Alien Polymorphism (4/14/10)
^ top
Home
| Blackboard
| Schedule
| Room Policies
| Syllabus
Help
| FAQ's
| HowTo's
| Links
Last Updated: April 05 2010 @12:29:19
|
|