-
Notifications
You must be signed in to change notification settings - Fork 0
Inheritance and Polymorphism
shape
is a superclass (or a parent class, or a base class). Rectangle
, Triangle
and Circle
are subclasses. They are an extension of the Shape
class: They cover Shape attributes/methods and adds new attributes/methods.
Arrow towards the super class denotes the inheritance relationship (Circle class is derived from Shape class)
'#' denotes the protected visibility modifier. A subclass cannot access superclass’s private members, if you want to have a data fields or method that can be accessed from subclasses, but not accessible from the other external classes, define them as protected.
We do not need to write superclass’s data fields and methods in the subclass. They are implicitly defined.
public class SubClassName extends SuperClassName {
// instance variables
// methods
}
The keyword super refers to the superclass and can be used to invoke the superclass’s methods and constructors
It can be used in two ways: 1) Call a superclass constructor 2) Call a superclass method
Calling constructor:
public class Student extends Person {
public double GPA;
Student() {
super();
GPA = 1.0;
}
Student(String name, int age, double GPA) {
super(name, age);
GPA = 1.0;
}
}
Calling methods: (Use of super.methodName() is only required if the subclass contains a method with the same name, and you need to call superclass method)
public class Student extends Person {
@Override
public String toString() {
return super.toString() + ", GPA: " + GPA;
}
}
When constructing an object of a subclass, the subclass constructor first invokes its superclass constructor
This process continues until the last constructor along the inheritance hierarchy is called. This is called constructor chaining:
public class Student extends Person {
public double GPA;
Student(String name, int age, double GPA) {
super(name, age);
GPA = 1.0;
}
}
In this example, constructor of Person will be invoked first, then Student constructor.
If a subclass constructor does not call any constructor, the compiler automatically puts
super() as the first statement. (If we did not put super(name, age);
in the example, the compiler would
automatically put super();
at the first line.)
Since subclass constructors automatically invoke superclass’s nor-arg constructor, we need to write no-arg constructor if we want to extend a class.
Difference between overloading and overriding is subtle, so it is possible to mix two terms. Simply, overloading means to define multiple methods with the same name but different signatures. Overriding means to provide a new implementation for a method in the subclass. @Override annotation can be used to avoid mixing two. When we use the annotation while we are not overriding a method, we will see an error. That way we can understand that we are doing something wrong. Below code shows an example of overriding and overloading together, also @Override annotation will be shown:
public class OverridingVsOverloading {
public static void main(String[] args) {
A a = new A();
a.p(10);
a.p(10.0);
}
}
class B {
public void p(double i) {
System.out.println(i * 2);
}
}
class A extends B {
// This method overrides the method in B
@Override
public void p(double i) {
System.out.println("Overriding.." + i);
}
// This method overloads the method in B
public void p(int i) {
System.out.println("Overloading.." + i);
}
}
You may want to prevent classes from being extended: Use the final modifier to indicate that a class is final and cannot be extended.
public final class Person {
public String name;
public int age;
Person() {
}
}
You also can define a method to be final: Final methods cannot be overridden.
public final void increaseAge() {
age = age + 1;
}
Polymorphism means that a variable of a supertype (an object of the super/parent class) can refer to a subtype (child/subclass) object.
A superclass variable can store subclass objects:
public static void main(String[] args) {
Shape a = new Circle();
Shape b = new Rectangle();
}
Here, declared type of object a is 'Shape', however its actual type is 'Circle'. With polymorphism, these two can be different.
We can define a Shape
array that can hold objects of Circle, Rectangle, Triangle and Shape. This is very helpful if we want to define a more general structure.
public static void main(String[] args) {
Shape[] array = new Shape[1000];
array [0] = new Circle();
array [1] = new Rectangle();
array [2] = new Shape();
}
We will see an example of dynamic binding by seeing following terms at first:
- Actual Type
- Declared Type
The type that declares a variable is called the variable’s declared type. A variable of a reference type (not a primitive type like int, float etc.) can hold a null value or a reference to an instance of the declared type. The instance may be created using the constructor of the declared type or its subtype (one of the subtypes, or sub-subtypes). The actual type of the variable is the actual class for the object referenced by the variable.
Which method is invoked by the variable is determined by the actual type and this is known as dynamic binding. Java decides which method is invoked at runtime
An example can be seen below:
public class DynamicBindingDemo {
public static void main(String[] args) {
// Declared type for o = ’Object’
// Actual type for o = ’Person’
Object o = new Person(); //Polymorphic Call
Person s = new Student();
method(o);
method(s);
}
public static void method(Object x) { //Dynamic Binding
System.out.println(x.toString());
}
}
We will see an example code that shows implicit and explicit casting, and usage of instanceof operator. Aim is to let compiler know that an object belonging to a superclass is also an instance of a subclass:
public static void main(String[] args) {
// Create and initialize two objects
Object object1 = new Teacher();
Object object2 = new Student();
// Display circle and rectangle
displayObject(object1);
displayObject(object2);
}
/** A method for displaying an object */
public static void displayObject(Object object) {
if (object instanceof Teacher) {
System.out.println("This is a teacher " +
((Teacher)object).toString());
}
else if (object instanceof Student) {
System.out.println("This is a student " +
((Student)object).toString());
}
}