Inheritance and Interfaces
Chapter 4
Basics
One of the pillars of object-orientation.
A new class is derived from an existing class:
1) existing class is called super-class
2) derived class is called sub-class
A sub-class is a specialized version of its super-class:
1) has all non-private members of its super-class
2) may provide its own implementation of super-class
methods
Objects of a sub-class are a special kind of objects of a super-class.
syntax
Syntax:
class sub-class extends super-class {
…
}
Each class has at most one super-class;
no multi-inheritance in Java.
No class is a sub-class of itself
Example
class A {
int i;
void showi() {
System.out.println("i: " + i);
}
}
class B extends A {
int j;
void showj() {
System.out.println(“j: " + j);
}
void sum() {
System.out.println("i+j: " + (i+j));
}
}
Testing class
class SimpleInheritance {
public static void main(String args[]) {
A supOb = new A();
B subOb = new B();
supOb.i = 10;
System.out.println("Contents of a: ");
supOb.showi();
subOb.i = 7; subOb.j = 8;
System.out.println("Contents of sub object: ");
subOb.showi(); subOb.showj();
System.out.println("Sum of I and j in b:");
subOb.sum();
}
}
Inheritance and Private Members
A class may declare some of its members private.
A sub-class has no access to the private members of its super-class:
class A {
int i;
private int j;
void setij(int x, int y) {
i = x; j = y;
}}
Class B has no access to the A’s private variable j.
This program will not compile:
class B extends A {
int total;
void sum() {
total = i + j;}}
Example
The basic Box class with width, height and depth:
class Box {
double width, height, depth;
Box(double w, double h, double d) {
width = w; height = h; depth = d;
}
Box(Box b) {
width = b.width;
height = b.height; depth = b.depth;
}
double volume() {
return width * height * depth;
}
}
BoxWeight class extends Box with the new weight variable:
class BoxWeight extends Box {
double weight;
BoxWeight(double w, double h, double d, double m) {
width = w; height = h; depth = d; weight = m;
}
BoxWeight(Box b, double w) {
Box(b);
weight = w;
}
}
Box is a super-class, BoxWeight is a sub-class
BoxWeight Demo
class DemoBoxWeight {
public static void main(String args[]) {
BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
BoxWeight mybox2 = new BoxWeight(mybox1,40);
double vol;
vol = mybox1.volume();
System.out.println("Volume of mybox1 is " + vol);
System.out.print("Weight of mybox1 is “);
System.out.println(mybox1.weight);
vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
System.out.print("Weight of mybox2 is “);
System.out.println(mybox2.weight);
}
}
Another sub class
Once a super-class exists that defines the attributes common to a
set of objects, it can be used to create any number of more specific
sub-classes.
The following sub-class of Box adds the color attribute instead of
weight:
class ColorBox extends Box {
int color;
ColorBox(double w, double h, double d, int c) {
width = w; height = h; depth = d;
color = c;
}
}
Referencing Sub-Class Objects
A variable of a super-class type may refer to any of its sub-class
objects:
class SuperClass { … }
class SubClass extends SuperClass { … }
SuperClass o1;
SubClass o2 = new SubClass();
o1 = o2;
However, the inverse is illegal:
o2 = o1 //INVALID
Example: Sub-Class Objects 1
class RefDemo {
public static void main(String args[]) {
BoxWeight weightbox = new BoxWeight(3, 5, 7, 8.37);
Box plainbox = new Box(5, 5, 5);
double vol;
vol = weightbox.volume();
System.out.print("Volume of weightbox is “);
System.out.println(vol);
System.out.print("Weight of weightbox is “);
System.out.println(weightbox.weight);
plainbox = weightbox;
Box plainbox=new BoxWeight(3,5,7,8.37);
vol = plainbox.volume();
System.out.println("Volume of plainbox is " + vol);
}
plainbox variable now refers to the WeightBox object.
Can we then access this object’s weight variable through plainbox?
No. The type of a variable, not the object this variable refers to,
determines which members we can access!
This is illegal:
System.out.print("Weight of plainbox is “);
System.out.println(plainbox.weight);
Super as a Constructor
Calling a constructor of a super-class from the constructor of a sub-
class:
super(parameter-list);
Must occur as the very first instruction in the sub-class constructor:
class SuperClass { … }
class SubClass extends SuperClass {
SubClass(…) {
super(…);
…
}
…
}
Example: Super Constructor
BoxWeight need not initialize the variable for the Box super-class, only
the added weight variable:
class BoxWeight extends Box {
double weight;
BoxWeight(double w, double h, double d, double m) {
super(w, h, d); weight = m;
}
BoxWeight(Box b, double w) {
super(b); weight = w;
}
}
Uses of Super
Two uses of super:
1) to invoke the super-class constructor
super();
2) to access super-class members
super.variable;
super.method(…);
Why is super needed to access super-class members?
When a sub-class declares the variables or methods with the
same names and types as its super-class:…
Super and Hiding
class A {
int i = 1;
}
class B extends A {
int i = 2;
System.out.println(“i is “ + i);
}
The re-declared variables/methods hide those of the super-class
class A {
int i;
}
class B extends A {
int i;
B(int a, int b) {
super.i = a; i = b;
}
void show() {
System.out.println("i in superclass: " + super.i);
System.out.println("i in subclass: " + i);
}
}
Multi-Level Class Hierarchy 1-2
Consider the Box class…
Adding weight variable to the Box class…
class BoxWeight extends Box {
double weight;
BoxWeight(BoxWeight ob) {
super(ob); weight = ob.weight;
}
BoxWeight(double w, double h, double d, double m) {
super(w, h, d); weight = m;
}
}
Hierarchy 3
Adding the cost variable to the BoxWeight class:
class Ship extends BoxWeight {
double cost;
Ship(Ship ob) {
super(ob); cost = ob.cost;
}
Ship(double w, double h,
double d, double m, double c) {
super(w, h, d, m); cost = c;
}
}
Demo
class DemoShip {
public static void main(String args[]) {
Ship ship1 = new Ship(10, 20, 15, 10, 3.41);
Ship ship2 = new Ship(2, 3, 4, 0.76, 1.28);
double vol;
vol = ship1.volume();
System.out.println("Volume of ship1 is " + vol);
System.out.print("Weight of ship1 is”);
System.out.println(ship1.weight);
System.out.print("Shipping cost: $");
System.out.println(ship1.cost);
vol = ship2.volume();
System.out.println("Volume of ship2 is " + vol);
System.out.print("Weight of ship2 is “);
System.out.println(ship2.weight);
System.out.print("Shipping cost: $“);
System.out.println(ship2.cost);}}
Constructor call order
Constructor call-order:
1) first call super-class constructors
2) then call sub-class constructors
In the sub-class constructor, if super(…) is not used explicitly, Java calls
the default, parameter-less super-class constructor
Polymorphism
Polymorphism is one of three pillars of object-orientation.
Polymorphism: many different (poly) forms of objects that share a
common interface respond differently when a method of that
interface is invoked:
1) a super-class defines the common interface
2) sub-classes have to follow this interface (inheritance), but are
also permitted to provide their own implementations (overriding)
A sub-class provides a specialized behaviors relying on the common
elements defined by its super-class
Polymorphism : behaviour
Suppose we have a hierarchy of classes:
1) The top class in the hierarchy represents a common interface to
all classes below. This class is the base class.
2) All classes below the base represent a number of forms of
objects, all referred to by a variable of the base class type.
What happens when a method is invoked using the base class
reference?
- The object responds in accordance with its true type.
What if the user pointed to a different form of object using the same
reference?
- The user would observe different behavior.
This is polymorphism.
Method overriding
When a method of a sub-class has the same name and type as a
method of the super-class, we say that this method is overridden.
When an overridden method is called from within the sub-class:
1) it will always refer to the sub-class method,
2) super-class method is hidden
class A {
int i, j;
A(int a, int b) {
i = a; j = b;
}
void show() {
System.out.println("i and j: " + i + " " + j);
}
}
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {
System.out.println("k: " + k);
}
When show() is invoked on an object of type B, the version of show()
defined in B is used:
class Override {
public static void main(String args[]) {
B subOb = new B(1, 2, 3);
subOb.show();
}
}
The version of show() in A is hidden through overriding.
Super and Method Overriding
The hidden super-class method may be invoked using super:
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {
super.show();
System.out.println("k: " + k);
}
}
The super-class version of show() is called within the sub-class’s
version
Dynamic method Invocation
Overriding is a lot more than the namespace convention.
Overriding is the basis for dynamic method dispatch – a call to an
overridden method is resolved at run-time, rather than compile-
time.
Method overriding allows for dynamic method invocation:
1) an overridden method is called through the super-class variable
2) Java determines which version of that method to execute based
on the type of the referred object at the time the call occurs
3) when different types of objects are referred, different versions of
the overridden method will be called.
A super-class A:
class A {
void callme() {
System.out.println("Inside A's callme method");}}
Two sub-classes B and C:
class B extends A {
void callme() {
System.out.println("Inside B's callme method");
}
}
class C extends A {
void callme() {
System.out.println("Inside C's callme method");
}
}
B and C override the A’s callme() method
Overridden method is invoked through the variable of the super-class type.
Each time, the version of the callme() method executed depends on the
type of the object being referred to at the time of the call:
class Dispatch {
public static void main(String args[]) {
A a = new A();
B b = new B();
C c = new C();
A r;
r = a; r.callme();
r = b; r.callme();
r = c; r.callme();
}
}
Abstract Method
Inheritance allows a sub-class to override the methods of its super-class.
In fact, a super-class may altogether leave the implementation details of a
method and declare such a method abstract:
abstract type name(parameter-list) ;
abstract void display(int);
kinds of methods:
1) concrete – may be overridden by sub-classes
2) abstract – must be overridden by sub-classes
It is illegal to define abstract constructors or static methods
Abstract Class
A class that contains an abstract method must be itself declared
abstract:
abstract class abstractClassName {
abstract type methodName(parameter-list) {
…
}
…
}
An abstract class has no instances - it is illegal to use the new
operator:
abstractClassName a = new abstractClassName();
It is legal to define variables of the abstract class type
abstractClassName a;
Abstract Sub-Class
A sub-class of an abstract class:
1) implements all abstract methods of its super-class, or
2) is also declared as an abstract class
abstract class A {
abstract void callMe();
}
abstract class B extends A {
int checkMe;
}
Abstract and Concrete Classes
Abstract super-class, concrete sub-class:
abstract class A {
abstract void callme();
void callmetoo() {
System.out.println("This is a concrete method.");
}
}
class B extends A {
void callme() {
System.out.println("B's implementation.");
}
}
Abstract Sub-Class
A sub-class of an abstract class:
1) implements all abstract methods of its super-class, or
2) is also declared as an abstract class
abstract class A {
abstract void callMe();
}
abstract class B extends A {
int checkMe;
}
Demo Figureclass example in class…
Demo Figureclass example in class…
abstract class Figure
{
double dim1;
double dim2;
Figure(double a, double b)
{
dim1 = a; dim2 = b;
}
abstract double area();
}
class Rectangle extends Figure
{
Rectangle(double a, double b)
{
super(a, b);
}
double area()
{
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
}
class Triangle extends Figure
{
Triangle(double a, double b)
{
super(a, b);
}
double area()
{
System.out.println("Inside Area for Triangle.");
return dim1 * dim2 / 2;
}
}
class AbstractAreas
{
public static void main(String args[])
{
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
Figure figref;
figref = r;
System.out.println(figref.area());
figref = t;
System.out.println(figref.area());
}
}
Uses of final
The final keyword has three uses:
1) declare a variable which value cannot change after initialization
2) declare a method which cannot be overridden in sub-classes
3) declare a class which cannot have any sub-classes
A method declared final cannot be overridden in any sub-class:
class A {
final void meth() {
System.out.println("This is a final method.");
}
}
This class declaration is illegal:
class B extends A {
void meth() {
System.out.println("Illegal!");
}
}
final and Early Binding
Two types of method invocation:
1) early binding – method call is decided at compile-time
2) late binding – method call is decided at run-time
By default, method calls are resolved at run-time.
As a final method cannot be overridden, their invocations are resolved
at compile-time. This is one way to improve performance of a
method call.
Preventing Inheritance with final
A class declared final cannot be inherited – has no sub-classes.
final class A { … }
This class declaration is considered illegal:
class B extends A { … }
Declaring a class final implicitly declares all its methods final.
It is illegal to declare a class as both abstract and final.
Object Class
Object class is a super-class of all Java classes:
1) Object is the root of the Java inheritance hierarchy.
2) A variable of the Object type may refer to objects of any class.
3) As arrays are implemented as objects, it may also refer to any array
Object class methods
Methods declared in the Object class:
1) Object clone() - creates an object which is an ideal copy of the
invoking object.
2) boolean equals(Object object) - determines if the invoking
object and the argument object are the same.
3) void finalize() – called before an unused object is recycled
4) Class getClass() – obtains the class description of an object at
run-time
5) int hashCode() – returns the hash code for the invoking object
6) void notify() – resumes execution of a thread waiting on the
invoking object
7) void notifyAll() – resumes execution of all threads waiting on
the invoking object
8) String toString() – returns the string that describes the
invoking object
9) three methods to wait on another thread of execution:
a) void wait()
b) void wait(long milliseconds)
c) void wait(long milliseconds, int nanoseconds)
Overriding object class methods
All methods except getClass, notify, notifyAll and wait can be
overridden.
Two methods are frequently overridden:
1) equals()
2) toString()
This way, classes can tailor the equality and the textual description of
objects to their own specific structure and needs.