JAVA 8 Inheritance
JAVA 8 Inheritance
Introduction
• Inheritance is one of the cornerstones of object-oriented
programming because it allows the creation of hierarchical
classifications.
• Using inheritance, you can create a general class that defines
traits common to a set of related items. This class can then be
inherited by other, more specific classes, each adding those
things that are unique to it.
• In the terminology of Java, a class that is inherited is called a
superclass. The class that does the inheriting is called a subclass.
• Therefore, a subclass is a specialized version of a superclass. It
inherits all of the members defined by the superclass and adds
its own, unique elements.
Inheritance Basics
• To inherit a class, you simply incorporate the
definition of one class into another by using the
extends keyword.
• Even though A is a superclass for B, it is also a
completely independent, stand-alone class.
• Being a superclass for a subclass does not
mean that the superclass cannot be used by
itself.
• Further, a subclass can be a superclass for
another subclass.
• You can only specify one superclass for any
subclass that you create.
• Java does not support the inheritance of
multiple superclasses into a single subclass.
You can, as stated, create a hierarchy of
inheritance in which a subclass becomes a
superclass of another subclass.
• However, no class can be a superclass of itself.
Member Access and Inheritance
• Although a subclass includes all of the
members of its superclass, it cannot access
those members of the superclass that have
been declared as private
• This program will not compile because the use
of j inside the sum( ) method of B causes an
access violation.
• Since j is declared as private, it is only
accessible by other members of its own class.
Subclasses have no access to it.
// Here, Box is extended to include weight.
// default constructor
BoxWeight() {
super();
weight = -1;
}
// default constructor
Shipment() {
super();
cost = -1;
}
double vol;
vol = shipment1.volume();
System.out.println("Volume of shipment1 is " + vol);
System.out.println("Weight of shipment1 is "
+ shipment1.weight);
System.out.println("Shipping cost: $" + shipment1.cost);
System.out.println();
vol = shipment2.volume();
System.out.println("Volume of shipment2 is " + vol);
System.out.println("Weight of shipment2 is "
+ shipment2.weight);
System.out.println("Shipping cost: $" + shipment2.cost);
}
}
• Volume of shipment1 is 3000.0
• Weight of shipment1 is 10.0
• Shipping cost: $3.41
• Volume of shipment2 is 24.0
• Weight of shipment2 is 0.76
• Shipping cost: $1.28
• The super( ) in Shipment calls the constructor
in BoxWeight. The super( ) in BoxWeight calls
the constructor in Box.
• In a class hierarchy, if a superclass constructor
requires parameters, then all subclasses must
pass those parameters “up the line.”
• This is true whether or not a subclass needs
parameters of its own.
When Constructors Are Executed
• When a class hierarchy is created, in what order are the
constructors for the classes that make up the hierarchy
executed?
• For example, given a subclass called B and a superclass called
A, is A’s constructor executed before B’s, or vice versa?
• The answer is that in a class hierarchy, constructors complete
their execution in order of derivation, from superclass to
subclass.
• Further, since super( ) must be the first statement executed in
a subclass’ constructor, this order is the same whether or not
super( ) is used.
• If super( ) is not used, then the default or parameter less
constructor of each superclass will be executed.
• Inside A's constructor
• Inside B's constructor
• Inside C's constructor
Method overriding
• In a class hierarchy, when a method in a subclass
has the same name and type signature as a
method in its superclass, then the method in the
subclass is said to override the method in the
superclass.
• When an overridden method is called from within
its subclass, it will always refer to the version of
that method defined by the subclass. The version
of the method defined by the superclass will be
hidden.
• The output produced by this program is
shown here:
• k: 3
• If you wish to access the superclass version of
an overridden method, you can do so by using
super.
• For example, in this version of B, the
superclass version of show( ) is invoked within
the subclass’ version. This allows all instance
variables to be displayed.
• If you substitute this version of A into the
previous program, you will see the following
output:
• i and j: 1 2
• k: 3
Overloading and overriding
• Method overriding occurs only when the
names and the type signatures of the two
methods are identical. If only names are
identical, then the two methods are simply
overloaded
• The output produced by this program is
shown here:
• This is k: 3
• i and j: 1 2
Dynamic Method Dispatch
• Method overriding forms the basis for one of
Java’s most powerful concepts: dynamic
method dispatch.
• Dynamic method dispatch is the mechanism by
which a call to an overridden method is
resolved at run time, rather than compile time.
• Dynamic method dispatch is important because
this is how Java implements run-time
polymorphism.
// Dynamic Method Dispatch
class A {
void callme() {
System.out.println("Inside A's callme method");
}
}
class B extends A {
// override callme()
void callme() {
System.out.println("Inside B's callme method");
}
}
class C extends A {
// override callme()
void callme() {
System.out.println("Inside C's callme method");
}
}
class Dispatch {
public static void main(String args[]) {
A a = new A(); // object of type A
B b = new B(); // object of type B
C c = new C(); // object of type C
A r; // obtain a reference of type A
r = a; // r refers to an A object
r.callme(); // calls A's version of callme
r = b; // r refers to a B object
r.callme(); // calls B's version of callme
r = c; // r refers to a C object
r.callme(); // calls C's version of callme
}
}
• Inside A's callme method
• Inside B's callme method
• Inside C's callme method
Why Overridden Methods?
• overridden methods allow Java to support
run-time polymorphism
• Dynamic, run-time polymorphism is one of the
most powerful mechanisms that object
oriented design brings to bear on code reuse
and robustness
Applying Method Overriding
// Using run-time polymorphism.
class Figure {
double dim1;
double dim2;
Figure(double a, double b) {
dim1 = a;
dim2 = b;
}
double area() {
System.out.println("Area for Figure is undefined.");
return 0;
}
}
class FindAreas {
public static void main(String args[]) {
Figure f = new Figure(10, 10);
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
Figure figref;
figref = r;
System.out.println("Area is " + figref.area());
figref = t;
System.out.println("Area is " + figref.area());
figref = f;
System.out.println("Area is " + figref.area());
}
}
• The output from the program is shown here:
• Inside Area for Rectangle.
• Area is 45
• Inside Area for Triangle.
• Area is 40
• Area for Figure is undefined.
• Area is 0
Using Abstract Classes
• to define a superclass that declares the
structure of a given abstraction without
providing a complete implementation of every
method
• Such a class determines the nature of the
methods that the subclasses must implement.
// A Simple demonstration of abstract.
abstract class A {
abstract void callme();
class B extends A {
void callme() {
System.out.println("B's implementation of callme.");
}
}
class AbstractDemo {
public static void main(String args[]) {
B b = new B();
b.callme();
b.callmetoo();
}
}
• It is not possible to instantiate an abstract class.
• class A implements a concrete method called callmetoo( ).
This is perfectly acceptable. Abstract classes can include as
much implementation as they see fit.
• Although abstract classes cannot be used to instantiate
objects, they can be used to create object references,
because Java’s approach to run-time polymorphism is
implemented through the use of superclass references.
• Thus, it must be possible to create a reference to an
abstract class so that it can be used to point to a subclass
object.
// Using abstract methods and classes.
abstract class Figure {
double dim1;
double dim2;
Figure(double a, double b) {
dim1 = a;
dim2 = b;
}
class AbstractAreas {
public static void main(String args[]) {
// Figure f = new Figure(10, 10); // illegal now
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
figref = r;
System.out.println("Area is " + figref.area());
figref = t;
System.out.println("Area is " + figref.area());
}
}
• As the comment inside main( ) indicates, it is
no longer possible to declare objects of type
Figure, since it is now abstract. And, all
subclasses of Figure must override area( ).
Using final with Inheritance
• The keyword final has three uses.
• First, it can be used to create the equivalent of
a named constant.
• This use was described in the preceding
chapter. The other two uses of final apply to
inheritance.
Using final to Prevent Overriding
• To disallow a method from being overridden,
specify final as a modifier at the start of its
declaration. Methods declared as final cannot
be overridden.
class A {
final void meth() {
System.out.println("This is a final method.");
}
}
class B extends A {
void meth() { // ERROR! Can't override.
System.out.println("Illegal!");
}
}
Using final to Prevent Inheritance
• Sometimes you will want to prevent a class
from being inherited. To do this, precede the
class declaration with final. Declaring a class
as final implicitly declares all of its methods as
final, too.
final class A {
// ...
}