Beruflich Dokumente
Kultur Dokumente
Context
Objectives
Study Planning
You should expect to spend approximately 9 hours studying this unit. You may find it
convenient to break up your study as follows:
Disk-based Content: 2¼
hours
Application: 3 hours
Set textbook Content: 1 hour
Reflection (On-line discussions, review 1 hour
questions):
Tutorial Work: 1 hour
Related Coursework: ¼ hour
Extension Work: ½ hour
Equipment/software required
1. Java: how to program. H. M. Deitel and P. J. Deitel, 3rd edition, Prentice-Hall, ISBN: 0-
13-012507-5
Online Resources:
1. Frequently-asked questions
2. Additional Source Code Examples
Introduction to unit 7
This is an important unit, since inheritance, and its implementation in Java via the extends,
interface and abstract keywords is something that almost all non-trivial Java programs
exploit.
After working through this module you may wish to return to earlier units to examine the
Java listings with a view to identifying the extent to which each embodies inheritance.
Examples include the listings for the CircleSquare application you used in unit 1, and the
development of the bouncing ball application in unit 2.
The Deitel & Deitel book provides much reference material on Java's implementation of
inheritance, and in the extension sesof this unit you are directed towards Sun's website
for additional sources of reference.
Inheritance is a key feature of object-oriented programming It embodies the idea that one
thing is `like' (or a `type of') another thing. Inheritance is implemented in Java using the
extends and implements mechanisms.
Here is a simple example. Suppose we are writing a computer program that allows the
user to draw diagrams. It understands rectangles, circles, lines and text. We could write
sections of program to handle each of these shapes, but if we did this we would soon find
that we were writing the same program lines over and over again.
Why? Because all these shapes have a lot in common. All have one or more lines with a
particular thickness and colour. All can be filled in with, perhaps, a different colour. All
have a particular position on the screen, and so on. However, there are also differences
between the different shapes. For example, the idea of `font' (typeface) is meaningful for
text, but has no meaning for a line or circle.
The way inheritance works is that we define a class (perhaps called Shape) that contains
all the program instructions. Then we define classes for each of the other shapes, which
contain only the instructions that are necessary for that particular shape. So in the class
`Text' (for example) that handles the drawing of text, we would include instructions for
processing different typefaces.
The class from which another class inherits is called its direct superclass or base class .
A class that does the inheriting is called the subclass or derived class.
The process of inheritances is also called specialization. The UML symbol for inheritance
is a large arrow pointing from the subclass to the base class, as shown below:
In UML notation, the figure below shows the notion that the class Car is a subclass of
Vehicle .
It is rather unfortunate that there is a lot of terminology associated with the concept of
inheritance. Very often there are different terms that mean the same thing. Object-
oriented programming is a widely-used, rapidly developing technique, and it is not
surprising that the terminology cannot be standardised as fast as the subject develops.
The relationships between classes can often be expressed more clearly on a diagram
than in text. The standard notation for this is called UML (unified modelling language).
The full UML specification is very long (currently 645 pages!), but will only require a few
symbols for this unit.
The classes are shown as rectangles. There are spaces in each class to write the
attributes and operations of that class. Remember, UML is a modelling language, so the
use of object-oriented modelling terms such as attribute and operation are used. A Java
programmer can take a model expression in UML and implement the model, so that the
modelled attributes and operations become appropriate variables and methods.
In the example above there aren't any attributes or operations, so these spaces are blank.
The large arrow denotes an inheritance relationship. This can be read as `Car is a
subclass of Vehicle', `Car is a type of Vehicle', `Car is a specialization of vehicle' or
`Vehicle is a base class for Car'.
In Java, the keyword extends denotes full inheritance. If a definition states that a new
class 'extends' another, this new class will inherits all the non-private methods (and
variables) of the class it extends
For example, suppose the class Shape has a method called draw() . If we define Line
as being a type of Shape as below:
Indirect inheritance
Indirect inheritance embodies the idea that one thing is a type of another thing, and that
thing is in turn a type of something else. For example, if C is a subclass of B , and B is a
subclass of A , then C is an indirect subclass of A . Indirect inheritance is handled
automatically in Java.
To extend the example above a little, suppose that we define a class called Moveable
that describes how to make an object moveable on the screen (in any useful drawing
program we would need to be able to move shapes around). But as well as moving
Shapes, suppose we have other moveable items (like gridlines or markers on the
screen). So a Gridline is a type of Moveable , while a Line and a Circle are
types of Shape , which is a type of Moveable . The outline of the Java program that
defines these relationships might be:
class Moveable
{
// methods that define the class Moveable
}
class Shape extends Moveable
{
// methods that define the class Shape, that are not
// included in class Moveable
}
class Circle extends Shape
{
// methods that define the class Circle, that are not
// included in class Moveable or class Shape
}
Multiple inheritance
Multiple inheritance embodies the idea that one thing is a type of more than one
other thing
True multiple inheritance is not handled in Java
Java supports something called `lightweight' multiple inheritance
In the previous example, Circle was a type of Shape , which was itself a type of
Moveable . These classes form a hierarchy with Moveable at the `top' and Circle at
the `bottom'. Circle was only indirectly a type of Moveable. Suppose we want to state
that a class is a direct subclass of two others. Here is an example. Suppose any object
that can receive input from the user is a subclass of KeyboardListener . Examples
might include buttons, menus, window borders, etc. Suppose
any object that can be displayed in a window is a subclass of Component (this is a real
Java entity, and will be described in more detail later).
Suppose we now define a class called MyButton which displays a button in a window.
This is a subclass of KeyboardListener (because we can activate the button by
pressing the space bar, or clicking the mouse). It is a subclass of Component because it
can be displayed in a window. But Component is not a subclass of
KeyboardListener . Why? Because there may be other classes that can be
displayed in a window, but cannot receive input (e.g., an icon, or an image). So these
classes do not form a hierarchy. MyButton is a subclass of both KeyboardListener
and Component.
You might think we could describe this in Java using something like:
Java does, however, support something called ' lightweight' multiple inheritance , using
interfaces .
Exercise 2 – UML-to-Java
Exercise 3 — Java-to-UML A
Stop!
Before you go any further, be absolutely certain that you understand the information
presented so far. The rest of the unit, and indeed the rest of the module, will make no
sense at all if you do understand.
The concept of an interface can initially be conceptually difficult. You may have to go over
the next few sections several times to be sure you understand.
But the use of interfaces is only an organisational feature; an interface cannot contain
any program instructions. It is not really obvious which of the two entities (
KeyboardListener or Component ) should be an interface and which a class. In reality,
Component is very complex, and is defined as a class, while KeyboardListener (which
only has a few methods) is defined as an interface.
Defining an interface
An interface is defined just like a class, but with the `interface' keyword rather than the
`class' keyword. The methods must be defined, but not implemented
interface KeyboardListener
{
void keyPressed();
void keyReleased();
}
We have said that the KeyboardListener has two methods: keyPressed() and
keyReleased() but we have not said how these methods are to be carried out. My
intention is that keyPressed() will be called whenever the user presses a key, and
keyReleased() when the key is released.
The use of interfaces seems quite complicated at first, and the student can't be blamed
for wondering whether their use gives any real benefits. The importance of interfaces
becomes apparent when programs become more complicated. Suppose I define a
method in Java like this:
Even though the use of interfaces does not limit the amount of program code the
programmer has to write, it does prevent the programmer making trivial errors that
cannot be detected by the compiler. It also help to clarify the structure of the program,
making it easier to maintain and update.
Providing a method in a subclass with the same name (and parameters) as in its base
class is called overriding the method. The subclass method takes precedence over the
base class method. This is usually the desired effect, except in constructors. The super
method invokes the base class constructor.
Suppose I define a class called Button, which displays a button on the screen. The
button is (for example) grey. The user can click the button and cause the program to
carry out an action. The Button has a method called paint() which causes it to
update its screen display. Now suppose I want to create a coloured button. Let's call this
class ColouredButton . A ColouredButton is exactly the same as a Button
except that :
the paint() method paints a coloured button rather than a grey one, and
when we create a ColouredButton we want to specify its colour
Java has a keyword for this: super . This means `call the constructor for this class's
super (base) class'. The super constructor takes the same arguments that the
constructor itself would take. So in the Button example, when we call super in the
ColouredButton constructor, we specify the text of the button just as if we were
creating a new Button object. So the constructor for ColouredButton becomes:
If you create a subclass of a class that was not written by yourself (e.g., one of Java's
many built-in classes), it is good practice to call super at the start of any constructor that
your new class over-rides. This will ensure that the base class is initialised correctly.
Failure to do this in Java leads to all sorts of bizarre errors which are hard to detect.
For another example of method overriding and inheritance look back at the unit 2 class
RandomBall , (in version 8 of the bouncing ball world) which overrode the move()
method to be random:
// RandomBall.java
public class RandomBall extends Ball
{
public RandomBall (int newX, int newY, int
newRadius,int newXMotion, int newYMotion)
{
// call the Ball constructor
super( newX, newY, newRadius, newXMotion,
newYMotion );
}
public void move()
{
// 50% chance of chaning X motion
if( Math.random() > 0.5 )
dx = -dx;
// 50% chance of changing Y motion
if( Math.random() > 0.5 )
dy = -dy;
// move centre of object
x = x + dx;
y = y + dy;
}
}
// class RandomBall
Abstract methods
The word `abstract' here has no connection at all with the normal meaning of the word
(e.g., `abstract art'). An abstract class is one for which no objects can exist. Here is an
example. Circles , Squares and Lines are Types of Shape . Any shape can be
drawn, so it is sensible for the Shape class to have a draw() method. However, a
Shape object itself cannot exist; only its subclasses Circle , Square and Line
can have real objects. So although Shape has a draw() method, this method is
abstract, as is the class itself. We might define the Shape class something like this:
abstract class Shape
{
// Shape variables go here
public abstract void draw();
}
The following line of Java :
Shape myShape = new Shape();
will produce an error message to the effect that Shape is abstract and cannot be
instantiated.
When we create the subclasses, they must provide draw() methods, because the
Shape class is abstract due to the abstract method draw().
As with the concept map from the earlier units, you can use the map below as a way
retrieve glossary entries. You might wish to re-visit this concept map (and perhaps
create / extend it for yourself on paper) as you progress through the module.
Activities
A class has been defined called MyShape. This class has the following variables and
methods:
class MyShape
Variables Methods
Public MyShape()
import java.applet.Applet;
import java.awt.*;
public class ShapeApplet extends Applet
{
MyCircle shape1;
MySquare shape2;
You need to define 2 new classes, called MyCircle and MyClass that both are direct
subclasses of MyShape . Each class should have a constructor method (setting initial values to
appropriate instance variable such as radius for the circle and sideLenth for the square),
and should also define a draw( Garphics g ) method that makes use of the inherited xPos
and yPos instance variables.
You can use the file Shape.html to load the applet into the appletviewer.
/*
double radius
double x
double y
Eight methods:
Six of the methods are simple: getter’s and setter’s for x, y, and radius.
There should also be a getArea method that returns the area (derived from the
radius)
A doesOverlap method. This method should accept a MyCircle as an argument,
and return true if this circle overlaps the circle that the method was
invoked on. [Note: two circles overlap if the sum of their radius' is
greater than the distance between their centers.
*/
//if the sum of their radius' is greater than the distance between
their centers.
public boolean doesOverlap(MyCircle otherCircle) {
double sum = otherCircle.radius + radius;
double distance = Math.sqrt(Math.pow((otherCircle.x - x), 2.0)
+ Math.pow((otherCircle.y - y), 2.0) );
return sum > distance;
}
}
package stuff;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
//i override the pain method on this JComponent to just paint a filled
rectangle
// the graphics object is passed to the method through OS calls and
you not need to worry about it.
@Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
g.fillRect(this.x, this.y, this.width, this.height);
}
Looking at the constructor, notice how it first sends a message to invoke it superclass
constructor (i.e. MyShape()), which will set up initial values for the inherited xPos and
yPos variables:
public MyCircle()
{
// call constructor of superclass
super();
radius = 20;
}
and then the MyCircle() constructor goes on to initialise its instance variable radius.
The draw() method draws a circle on the argument g making use of the MyCircle's
instance variable radius:
The definition of MySquare follows just the same pattern (See listing MySquare.java).
Notice the use of the wildcard '*' in the use of the command javac. This means that all
files ending in ".java" are compiled — it can save a few commands when working with
a program made up of many classes (all stored in the current directory).
A class has been defined called MyShape. This class has the following variables and
methods:
class MyShape
Variables Methods
Public MyShape()
import java.applet.Applet;
import java.awt.*;
public class ShapeApplet extends Applet
{
MyCircle shape1;
MySquare shape2;
You need to define 2 new classes, called MyCircle and MyClass that both are direct
subclasses of MyShape . Each class should have a constructor method (setting initial values to
appropriate instance variable such as radius for the circle and sideLenth for the square),
and should also define a draw( Garphics g ) method that makes use of the inherited xPos
and yPos instance variables.
You can use the file Shape.html to load the applet into the appletviewer.
Looking at the constructor, notice how it first sends a message to invoke it superclass
constructor (i.e. MyShape()), which will set up initial values for the inherited xPos and
yPos variables:
public MyCircle()
{
// call constructor of superclass
super();
radius = 20;
}
and then the MyCircle() constructor goes on to initialise its instance variable radius.
The draw() method draws a circle on the argument g making use of the MyCircle's
instance variable radius:
The definition of MySquare follows just the same pattern (See listing MySquare.java).
Notice the use of the wildcard '*' in the use of the command javac. This means that all
files ending in ".java" are compiled — it can save a few commands when working with
a program made up of many classes (all stored in the current directory).
notice the reduced yPos of the square (from the default 50) and the increased xPos of the
circle (from the defalt 50) — this shows the success of the invocation of the inherited
methods through the sending of the setX() and setY() messages in ShapeApplet.java.
/*
Zener.java
This program displays a random Zener card. Zener cards are widely used in
research
in parapsychology (e.g., extra-sensory perception). There are only five
different
card types, called `waves', `cross', `circle', `square' and `star'. Many
experiments hinge on people attempting to guess (or determine by psychic
means!)
which card will be drawn from the pack next.
Anyway, this applet simply displays a random Zener symbol each time it is
started. So the display will be any one of the following images:
(Note that you will only see the images if you are looking at the HTML
version of this
file, Zener.java.html).
The Zener symbols are stored in GIF (image) files, so the `star'
expects to find the image files in the same directory as the java `.class'
as a separate class. All these classes have something in common: the ability
to
display an image in a GIF file. The difference between classes is the exact
name
needed by every card. Then we create classes called `Wave', `Square', etc.,
which implement what is different about each card. It turns out that the
classes that implement the individual classes are very simple; most of the
Note also that this program is very long for what it does; there are much
simpler
*/
import java.applet.Applet;
import java.net.URL;
import java.awt.*;
/*
class Zener
called), it creates a new object of one of the Card subclasses, and calls its
`draw()' operation.
*/
Card card;
switch (cardNumber)
{
case 0: card = new Waves(); break;
// files into memory. The Card object we are defining does not. So we
will
// current applet. The card will then call the operations in the
card.ownerApplet = this;
// So now we've created the `card' object and told it the applet to
use for
// screen.
card.draw(g);
}
/*
class Card
This class provides the functionality that is common to all the different
cards
*/
/*
The attribute `ownerApplet' will be set to indicate the applet that owns this
card object. This will be used to load the image file into memory before
image loading facilities in the Card class, which would be a waste of time
*/
Applet ownerApplet;
/*
drawImageFile
*/
// The getImage operation loads an image from a GIF file into an Image
object.
// If we assume that the image files are in the same directory, then
we
g.drawImage(image, 0, 0, ownerApplet);
/*
draw
*/
/*
Notes that these classes are very simple; they have only one operation (draw)
which
*/
drawImageFile(g, "zenerWaves.gif");
drawImageFile(g, "zenerCross.gif");
}
class Circle extends Card
drawImageFile(g, "zenerCircle.gif");
drawImageFile(g, "zenerSquare.gif");
drawImageFile(g, "zenerStar.gif");
}
(1) Study the example program Zener.java and answer the questions in it.
NOTE: For the applet to work you need to have the GIF image files in the same
directory as the Java source file:
zennerWaves.gif
zennerSquare.gif
zennerCircle.gif
zennerStar.gif
zennerCross.gif
The screen should look similar to the following run:
(3) Make the applet change the displayed shape, i.e. make the screen look these
different ways:
Discussion of notice the reduced yPos of the square (from the default 50) and the
increased xPos of the circle (from the defalt 50) — this shows the success of the
invocation of the inherited methods through the sending of the setX() and setY()
messages in ShapeApplet.java .
Discussion of Activity 2
Zener.java listing
The class Card has been declared as abstract because it is a class for which we never
want to create an object — we shall only create objects based on the subclasses of
class Card. Making a class abstracts requires the programmer to write subclasses which
are not abstract. The benefit of having an abstract class is that we can create a vathat
can refer to any Card object, i.e. a variable that can refer to any object based on any
subclass of this abstract class.
/// QUESTION ///
// why is this method `abstract'?
abstract public void draw(Graphics g);
A variable that has been declared to refer to objects of a superclass can only have
messages sent to it that are in the protocol (public and protected methods) defined in
the superclass. Therefore, if we wish some variable to be able to refer to different
subclass objects of the Card class, and to invoke polymorphism by the sending of
draw() messages, we have to ensure that the method draw() occurs in the protocol of
the superclass. Hence we declare an abstract method draw() in the abstract class Card.
Each non-abstract subclass will have to define its own implementation of the draw()
method.
(2) As usual we need to run the command line Java compiler with our Java source file:
The file Zener.html is a simple HTML file to execute the compiled Zener.class.
You will notice when you compile Zener.java that a number of ".class" files appear in
your directory, since there are a number of different classes defined in the one source
file (mainly the subclasses of the Card class).
(3) To get the applet to change the card it is showing we need to make the Zener applet
object invoke its paint() method. We can do this by causing a repaint() message to be
sent — for example by resizing the applet's window, or by covering and then revealing
the applet's window:
Since the selection of the card displayed is random, you may have to reisize the window
two or three times to get a different picture.
Look at the program Inheritance1.java and try to work out what display it will produce.
You can use the following html file to run the applet with the appletviewer:
<BODY>
<APPLET CODE="Inheritance1.class" height=100 width=200></APPLET>
</BODY>
When you think you've figured it out, compile and run the program and check your
answer
Inheritance issues
<BODY>
<APPLET CODE="Inheritance1.class" height=100 width=200></APPLET>
</BODY>
The steps will be numbered, to help keep track of what is happening to which object.
1) When the new Inheritance1 object is created, is first creates its instance variables
1.1) So a variable s is created, able to refer to String objects. Although for now the s
variable of the Inheritance1 object is null (not referring to any String object):
String s;
public Inheritance1()
{
s = "aaa";
}
this assigns the variable s to refer to a new String object with the value "aaa"
1.3) Next the Inheritance1 object, since it is an applet object, is sent a repaint()
message (this happens when a new applet object is created). When the Inheritance1
object receives the repaint() message, it executes its paint() method:
1.3.1) The first statement of the paint() method of the Inheritance1 object declares a
new, local to the method, variable i2. This variable is made to refer to a new
Inheritance2 object:
1.3.1.1) A new object of the class Inheriatance2 is created. The class Inheritance2 is
a subclass of the class Inheritance3, and therefore inherits the instance variables and
methods of Inheritance3.
So this new Inheritance2 object inherits the instance variable s, that is initialised to refer
to the String "ccc":
class Inheritance3
{
String s = "ccc";
// rest of class
1.3.1.2) Next the new Inheritance2 object executes its constructor, Inheritance2():
public Inheritance2()
{
super();
s = s + "bbb";}
1.3.1.2.1) The first statement of the Inheritance2() constructor invokes the constructor
of its superclass, in this case the constructor Inheritance3().
super();
The Inheritance3() constructor first invokes its superclass consuctor (i.e. Object() ),
and then assigns a new value to instance variable s. This new value of instance variable
s is a reference to the String "ddd":
public Inheritance3()
{br>super();
s = "ddd";
}
1.3.1.2.2) The second statement of the Inheritance2() constructor makes the instance
variable s refer to the String object created by concatenating is current String "ddd" with
the String "bbb".
s = s + "bbb";
Thus the instance variable s of the Inheritance2 object i2 now refers to the String
"dddbbb".
1.3.2) The second statement of the paint() method of the Inheritance1 object declares
a new, local to the method, variable s. NOTE: Any statements this paint() method will
now refer to this local variable s, not the Inheritance1.s instance variable.
You should avoid, wherever possible, having local variables with the same name as
instance or class variables.
This local variable is made to refer to the same String returned as a reply from sending
the message getData(); to the Inheritance2 object i2:
String s = i2.getData();
This results in the getData() method being invoked for the object i2.
1.3.2.1) The getData() method simple returns a reference to the same String as the
Inheritance2's instance variable s :
public String getData()
{
return s;
}
Since the instance variable s of Inheritance2 object i2 refers to the String "dddbbb", a
reference to this String is returned as a reply by this method.
1.3.3) The third statement of the paint() method of the Inheritance1 object sends a
drawString() message to the Graphics object:
This results in the value of the local variable s (i.e. the reference to the String "dddbbb")
being sent along with the co-ordinates (20, 20) to be drawn on screen.
Exercises
Complete the following statements that summarise the concepts explored in the
'Inheritance' section of this unit:
The object-oriented feature of ___________ embodies the idea that one thing is
similar to or a ______________ of another thing.
In Java full inheritance is declared with the use of the keyword ________.
Discussion of Exercise 1
Inheritance Summary
Write Java ‘class’ statements that define in outline the model shown in the diagram
(don’t define any operations)
Discussion of Exercise 2
UML-to-Java
From the UML diagram we can see that class Vehicle is a class that does not explicitly
extend any other class:
class Vehicle
{
}
The class Car is show by the arrow in the UML diagram to be a subclass of class
Vehicle, so when we define Car we state that it extends the class Vehicle:
Draw a UML diagram to show the relationships between classes expressed in the
following Java outline:
class Moveable
{
// methods that define the class Moveable
}
class Shape extends Moveable
{
// methods thdefine the class Shape, that are not
// included in class Moveable
}
class Circle extends Shape
{
// methods that define the class Circle, that are
not
// included in class Moveable or class Shape
}
Discussion of Exercise 3
Java-to-UML A
Class Movable is not explicitly a subclass of any other class (although it must then
implicitly be a subclass of Object). So we just draw a rectangle for Movable.
Class Shape is a subclass of Movable, so we draw an arrow from the rectangle for Shape
to Movable.
Class Circle is a subclass of class Shape, so we draw an arrow from the rectangle for
Circle to Movable .
Exercise 4 — Multiple inheritance
"Any object that can receive input from the user is a subclass of
InputReceiver . Examples might include buttons, menus, window
borders, etc. Any object that can be displayed in a window is a subclass of
Component . The class called MyButton displays a button in a window. This
is a subclass of InputReceiver (because we can activate the button by
pressing the space bar, or clicking the mouse). It is a subclass of
Component because it can be displayed in a window. Icon and Image are
subclasses of Component , but not subclasses of InputReceiver . "
Can the system be reorganised so that it does not exhibit multiple inheritance?
Discussion of Exercise 4
Multiple inheritance
If we make InputReceiver a subclass of Component this would avoid the problem of the
multiple inheritance. However, in reality perhaps not all objects that receive input are
displayable on screen, so this may not replicate the real system.
Complete the following statements that summarise the concepts explored in the
'Interfaces' section of this unit:
Discussion of Exercise 5
Interfaces summary
interface KeyboardListener
{
void keyPressed();
void keyReleased();
}
Show this interface on a UML diagram -- both ways -- including the operations.
Discussion of Exercise 6
or
Note that the second method is neater, but does not allow the operations to be seen
Exercise 7 — Java-to-UML B
Draw a UML diagram to show the relationships between classes expressed in the
following Java outline:
class Component
{
}
interface KeyboardListener
{
void keyPressed();
void keyReleased();
}
Discussion of Exercise 7
ava-to-UML B
We show that MyButton is a subclass of Component in the usual way — with an arrow
from class MyButton to class Component.
We show that MyButton implements the interface KeyboardListener with an arrow from
class MyButton to the rectangle labelled <<interface>> KeyboardListener (to explicitly
show that KeyboardListener is an interface).
Exercise 8 — English-to-UML
The following text describes the inheritance relationships between a small number of
types of animal.
"Reptiles and mammals are types of animal. Snakes and tortoises are types of reptile.
Dogs, cats and platypuses are types of mammal. All reptiles are types of `egg-laying
animal', as are platypuses. Dogs and cats are types of `furry animal'. Tortoises are
types of `animals with shell. "
Write Java 'class' and 'interface' definitions that embody the inheritance relationships
described. For example, the fact that `cats are types of mammal' can be represented
as:
You are advised to make a UML diagram showing the inheritance relationships between
these classes. You must avoid multiple inheritance by defining some interfaces.
Discussion of Exercise 8
English-to-UML
// Animals1.java
// This fragment of Java models the following class hierarchy
// Kevin Boone, August 1999
class Animal
{
}
interface Furry
{
}
interface LaysEggs
{
}
interface HasShell
{
}
class Mammal extends Animal
{
}
class Reptile extends Animal implements LaysEggs
{
}
class Dog extends Mammal implements Furry
{
}
class Platypus extends Mammal implements LaysEggs
{
}
class Snake extends Reptile implements LaysEggs
{
}
class Tortoise extends Reptile implements HasShell, LaysEggs
{
}
We can generalise the MyShape class by providing an abstract draw() method for the
classes MyCircle and MySquare to override.
The advantage of this means that a MyShape variable will be able to refer to an object
that is from any subclass of MyShape, and we can send that variable draw() messages.
The message draw() will be in the protocol for MyShape since it is defined as an
abstract class.
So:
Discussion of Exercise 9
Notice, we must now make the class MyShape abstract, since any class with one or
more abstract methods must be made an abstract class (since we cannot create
instances of classes with abstract methods). If we try to compile MyShape as a non-
abstract class with an abstract method, we get the following error message:
1 error
import java.awt.*;
abstract class MyShape
{
// instance variables
ICT xPos;
ICT yPos;
// constructor
public MyShape()
{
xPos = 50;
yPos = 50;
}
////////
public void setX(ICT newX)
{
if(newX > -1)
xPos = newX;
else
xPos = 0;
}
public void setY(ICT newY)
{
if(newY > -1)
yPos = newY;
else
yPos = 0;
}
// abstract method draw()
abstract void draw( Graphics g );
} // class
We don't need to change either MyCircle or MySquare — both these classes still extend
(subclass) the MyShape class and define their own constructor and draw() methods.
We now need to modify the ShapeApplet class, to use a single variable able to refer to
an object of class MyShape:
MyShape shape;
and we change the rest of the codeso that the shape variable refers to the new
MyCircle and then MySquare objects:
import java.applet.Applet;
import java.awt.*;
public class ShapeApplet extends Applet
{
MyShape shape;
public void paICT( Graphics g )
{
shape = new MyCircle();
shape.setX(100);
shape.draw( g );
shape = new MySquare();
shape.setY(20);
shape.draw( g );
}
}
Review Questions
Review question 1
In `true' multiple inheritance, a subclass may inherit from two base classes that have a
method with the same name. For example, suppose we have a class called `A' and a
class called `B', and both have a method called `test()'. Class `C' is a subclass of both A
and B, and it does not have its own `test()' method. So if we call the method C.test(),
does it call A.test() or B.test()? This confusion is one of the arguments used by the Java
developers for disallowing multiple inheritance in Java. Suppose we have an interface
(not a class) called A and a class called B, and both have a method `test()'. What
happens if class C extends B and implements A, and we call C.test()? How does this
avoid the problem?
If we call C.test(), and C does not have its own `test()' method, then we get A.test(). The
interface B only specifies that there is a test() method, it does not provide any
implementation for it. So in practice there is no ambiguity about which method to call.
Review question 2
Conceptually an interface is the same as an abstract class whose methods are all
abstract.
interface MyInterface
{
void method1();
void method2();
}
Review question 3
Super calls a class's base class constructor to be called. Normally when we over-ride a
constructor we want to provide methods that add to the functionality of the base class
constructor. Super provides a mechanism for doing this.
Review question 4
Inheritance can be used to represent the `type of' relationship (e.g., a business
customer is a type of customer).
Can it also be used to represent the `part of' relationship (e.g., wheels are part of a
car?)
There are some similarities between the `part of' and `type of' concepts in object
orientation. For example, in the same way that we say that:
"A brick is a part of a wall, and a wall is a part of a hour, therefore a brick
is a part of a house''.
class House
{
Wall walls[];
}
Review question 5
A display screen, however, is a type of output device. So in this case we could write:
class OutputDevice
{
void displayCharacter(char c)
{
// method to display character `c' on the device
}
}
class DisplayScreen extends OutputDevice
{
}
So far, so good. Now consider the touch-screen display. These are commonly used in
information kiosks and museum displays. The touch screen displays information, put it
provides information the computer when the users touches the screen. So is it an input
device or an output device, or both? Ideally we would like to say
But we can't do this, because this is multiple inheritance, which is not allowed. To what
extent does the Java `interface' mechanism allow us to represent the notion of a touch
screen as an input device and an output device? Try to write some Java code that
defines a TouchScreen class and its base classes.
Discussion of Review Question 5
One solution might be to make both the base classes interfaces, and implement the
input and output methods in the TouchScreen() class
class InputDevice
{
char getLastCharacterEntered();
}interface OutputDevice
{
void displayCharacter(Char c);
}
class TouchScreen implements InputDevice, OutputDevice
{
void displayCharacter(Char c)
{
// implement the method here
}
char getLastCharacterEntered()
{
// implement the method here
}
}
The problem with this is the use of the interfaces doesn't really achieve very much. If a
TouchScreen displays data very much like an ordinary display screen (and it does), then
it is pointless to re-implement displayCharacter() here when we have probably already
implemented it for the DisplayScreen class. We might be able to get round this by using
the displayCharacter() method in
This process is called delegation. It has been argued by some Java authorities that the
use of delegation can totally obviate the need for multiple inheritance. This remains a
controversial statement.
Discussion Topics
One example of real-world dimond of death situations is where people, or objects, have
multiple roles or functions. For example a company might have a gerenal class
Employee, and subclasses FullTimeEmployee and PartTimeEmployee (each with
different methods for tax, salary, holiday calculations and hiring-firing procedures etc.).
There mabe job sub-classes of each class, e.g. Manager, OfficeWorker, FactoryWorker.
There may be specific jobs, such as Machinist, subclass of FactoryWorker. So we could
have Machinish having 2 direct superclasses: FactoryWorker and FullTimeEmployee,
also this factory worker might also do extra work part time, and so also be a subclass of
PartTimeEmployee.
Another real-world example could be for a factory that makes kitchen utensils. Consider
a superclass Utensil (or Product) with subclasses BottleOpener and Corkscrew. Now
consider an object that is a combined bottle opener and corkscrew. These classes may
define operations such as stresses and strains, manufactory operations that can be
applied to them etc.
The problem with the structure is ambiguity of inheritance. Consider a method M()
defined in class A. Let us assume that this method is overriden in class C, but not in
class B. Therefore class B objects use the inherited method M() from class A. If class D
does not override method M(), should a class D object inherit method M() from its
superclass B (and therefore class A), or should class D inherit the overridden method
from its superclass C? This is a problem of multiple-inheritance.
Considering these issues, do you think multiple inheritance is a good thing or a bad
thing in programming?
You might like to look into some of the previous discussion on this subject. Try doing a
Web search for 'multiple inheritance'
Multiple inheritance
more complex class hierarchies (harder to create, debug, understand and work
with)
issues of resolving inheritance from different superclasses
difficulties in converting multiple inheritance object-oriented programs / designs
into languages that only support single inheritance (no problems the other way
around)
Additional Content
Additional reading
Additional Exercises
Extension exercises
A `mix-in' class is one that provides a small amount of functionality. Mix-ins are intended
to simplify implementation; a mix-in class rarely models a real-world entity.
Here is an example. It may be useful to allow objects to be able to save their states to a
disk file. For example, when I start my word processor, its appearance is very much as
it was when I last used it (position on screen, layout of buttons, etc). Clearly the objects
that model the screen appearance are able to `remember' their variables from the last
use of the program. The programmer may get this feature by defining a class called,
say, CanSaveToDisk , and making all other classes subclasses of CanSaveToDisk. This is
an example of a mix-in class; it provides a small, well-defined piece of program
functionality.
Why?
Reflect back to the 'dimond of death' and problems of multiple inheritance — the use of
`mix-in' programming presents a particular problem in this regard. Why?
End of Unit Review
Before proceeding to the next unit you should work through this set of review questions.
When you have completed the questions you will be able to obtain the answers for
future reference.
Your performance with these questions will not affect your grade for the module, but
may be monitored so that your tutor can be alerted if you are having difficulty.
Please contact your tutor if you feel you have not done as well as you expected.