3.Inheritance

Extending Classes

  • The keyword extends indicates that you are making a new class that derives from an existing class

  • The existing class is called the superclass, base class, or parent class

  • The new class is called subclass, derived class or child class

  • A subclass can add fields and it can add or override methods of the superclass

  • However, inheritance can never take away any fields or methods

  • The call using super must be the first statement in the constructor for the subclass

  • The super keyword has two meanings: to invoke a superclass method, and to invoke a superclass constructor

class Employee

{

public Employee(String n, double s) { ... }

public double getSalary() { ... }

}

class Manager extends Employee

{

public Manager(String n, double s, double b) {

super(n, s); // Invoke Employee's superclass constructor

}

public double getSalary() {

double baseSalary = super.getSalary();

return baseSalary + bonus;

}

}

Employee emp = new Employee("Carl", 80000);

Manager boss = new Manager("Harry", 150000);

e = emp;

e = boss;

e.getSalary(); // picks getSalary of Manager

Polymorphism

    • The fact that an object variable (such as the variable e) can refer to multiple actual types is called polymorphism

    • Automatically selecting the appropriate method at runtime is called dynamic binding

    • In Java, object variables are polymorphic, A variable of type Employee can refer to an object of type Employee or its any subclass (Manager)

    • However superclass variable e could call only superclass methods, even when it points to subclass Manager object

    • You cannot assign a superclass reference to a subclass variable, since subclass variable could not invoke subclass specific methods on superclass object

    • When you override a method, the subclass method must be at least as visible as the superclass method. In particular, if the superclass method is public, then the subclass method must also be declared as public.

    • It is a common error to accidentally omit the public specifier for the subclass method. Then the compiler complains that you try to supply a weaker access privilege

Preventing Inheritance: Final Classes and Methods

  • Classes that cannot be extended are called final classes (e.g. String class)

  • You can also make a specific method in a class final. No subclass can override that method

  • If a class is declared as final, only the methods, not the fields, are automatically final

  • Efficiency : Dynamic binding has more overhead than static binding, hence slower.

  • Safety : Full control that invoked method by base class reference would not change the behavior (by sub class method override)

final class Executive extends Manager

{

...

}

class Employee

{

public final String getName() { ... }

}

Casting

    • Casting is done to use an object in its full capacity after its actual type has been forgotten by variable of super class

    • Casting is done to invoke subclass method i.e. not present in superclass

    • Casts are commonly used with generic containers such as ArrayList class from Object type to specific type

    • You can cast only within an inheritance hierarchy

    • Use instanceof to check before casting from a superclass to a subclass

    • Compile-time error for out of inheritance hierarchy casting

    • Runtime error for casting superclass as subclass

Employee e1 = new Employee("Carl", 80000);

Employee e2 = new Manager("Harry", 150000);

Manager m = null;

if (e2 instanceof Manager) { \\ Check to ensure casting is done for valid case, otherwise exception could be thrown

m = (Manager) e2;

m = (Manager) e1; \\ This will throw Java runtime exception and needs to catch the exception

Date d = (Date) e1; \\ This will give Java compile-time error because Date is not a subclass of Employee

Abstract Classes

    • Abstract Method does not have an implementation only signature

    • Abstract Method are required if no default implementation is available in super class

    • A class with one or more abstract method must be abstract class

    • Abstract class cannot be instantiated, however variables could be created

    • Abstract class could have zero abstract methods

    • Abstract class could have concrete data and methods

    • Subclass define abstract methods

    • Subclass which defines all abstract methods is not abstract class

    • Subclass which define some (not all) abstract methods is abstract class as well

abstract class X {

public abstract show() { ... }

public String getName() { return name;}

private String name;

}

class Y extends X {...}

X x = new Y();

Protected Access

    • Restrict superclass method access to subclass

    • Allow subclass method to access superclass field

    • Subclass object could only access subclass object's superclass field, not of other superclass objects

    • clone method of Object class is good example of protected method

    • private - Visible to class only

    • public - Visible to the world

    • protected - Visible to all subclasses (including other packages)

    • default - Visible to the package. No modifiers are needed

Multiple Inheritance

  • When one class extends more than one classes then this is called multiple inheritance.

  • For example: Class C extends class A and B then this type of inheritance is known as multiple inheritance.

  • Java doesn’t allow multiple inheritance to prevent the ambiguity by Diamond problem

class A {}

class B {}

class C extends A,B () // Multiple inheritance is not supported in java

Diamond Problem

    • Suppose multiple inheritance class D extends both classes B & C

    • Lets assume class B & C both extend from class A and override a method in A in their own way

  • Because D is extending both B & C so if D wants to use the same method which method would be called (the overridden method of B or the overridden method of C).

  • Ambiguity. That’s the main reason why Java doesn’t support multiple inheritance.

Implement multiple interface in a class

    • A class can implement any number of interfaces. In this case there is no ambiguity even though both the interfaces are having same method.

  • Why? Because methods in an interface are always abstract by default, which doesn’t let them give their implementation (or method definition ) in interface itself.

interface X { public void myMethod(); }

interface Y { public void myMethod(); }

class JavaExample implements X, Y { public void myMethod() { System.out.println("Implementing more than one interfaces"); } public static void main(String args[]){ JavaExample obj = new JavaExample(); obj.myMethod(); } }

Interface with Default Method

  • Java 8 supports default methods where interfaces can provide default implementation of methods.

  • And a class can implement two or more interfaces.

  • In case both the implemented interfaces contain default methods with same method signature, the implementing class should explicitly specify which default method is to be used or it should override the default method.

  • If we remove implementation of default method from “TestClass”, we get compiler error.

// A simple Java program to demonstrate multiple

// inheritance through default methods.

interface PI1

{

// default method

default void show()

{

System.out.println("Default PI1");

}

}

interface PI2

{

// Default method

default void show()

{

System.out.println("Default PI2");

}

}

// Implementation class code

class TestClass implements PI1, PI2

{

// Overriding default show method

public void show()

{

// use super keyword to call the show

// method of PI1 interface

PI1.super.show();

// use super keyword to call the show

// method of PI2 interface

PI2.super.show();

}

public static void main(String args[])

{

TestClass d = new TestClass();

d.show();

}

}

  • If there is a diamond through interfaces, then there is no issue if none of the middle interfaces provide implementation of root interface.

  • If they provide implementation, then implementation can be accessed as above using super keyword.

// A simple Java program to demonstrate how diamond

// problem is handled in case of default methods

interface GPI

{

// default method

default void show()

{

System.out.println("Default GPI");

}

}

interface PI1 extends GPI { }

interface PI2 extends GPI { }

// Implementation class code

class TestClass implements PI1, PI2

{

public static void main(String args[])

{

TestClass d = new TestClass();

d.show();

}

}

Object: The Cosmic Superclass

    • The Object class is the ultimate ancestor - every class in Java extends Object (However you never write it)

    • Variable of type Object could be used to refer objects of any type

    • The equals method in Object class tests whether two objects point to same memory

    • Override equals() method if you wanna define your equality of object

    • Override toString() method for printed representation of class

    • Whenever object is concatenated to String using the "+" operator, Java compiler invoke toString method

    • Object class defines the toString() to print class name and memory location of object

    • toString() method is great debugging tool for traces

class X extends Object

Object o = new X();

X x = (X) o; // Object of X could be used after the casting

class X {

public boolean equals (Object other) {

if (this == other) return true; \\ point to same objects

if (other == null) return false;

if (getClass() != other.getClass()) return false; \\ both objects must belong to same class

if (!super.equals(other)) return false; \\ subclass should call for superclass check

X ox = (X) other;

return name,equals(ox.name);

}

public String toString() {

return super.toString() + getClass.getName() + " (name=" + name + " )";

}

}

String message = "Message " + x;

Methods

java.lang.Object

    • Class getClass() - returns a class object that contains information about the object

    • boolean equals(Object otherObject) - compares if the objects point to the same memory

    • Object clone() - creates a clone of object by allocating memory and copy current object to new object by memory copy

    • String toString() - returns a string that represents the value of this object

java.lang.Class

    • String getName() - returns the name of this class

    • Class getSuperClass() - returns the superclass of this class as a Class object

ArrayList

    • Array lists are array like objects that can grow and shrink automatically without you needing to write any code

    • Array are a feature of Java language with array type T[] for each element type T

    • ArrayList class is a library class defined in java.util package, which holds elements of type Object

    • Setting ArrayList initial capacity is optional

    • ArrayList like arrays are zero based

    • ArrayList set() should be called only for existing index to replace, for adding use add() instead

    • On rare occasions, array lists are useful for heterogeneous collections

    • Consider using linkedlist for element operations (add\remove) in middle of array list

ArrayList arr = new ArrayList();

arr.ensureCapacity(100); // set initial capacity - this is optional

arr.add(new X());

ArrayList arr2 = new ArrayList(100); \\ pass initial capacity

arr2.size();

arr2.trimToSize(); \\ This trims the memory block to holds current no of elements and garbage collector reclaim excess memory

arr.set(i, boss); \\ a[i] = boss;

Employee e = (Employee) arr.get(i); \\ cast since return type is Object

X[] a = new X[arr.size()];

arr.toArray(a); \\ Convert array list to array when you are done adding elements to array list

int n = arr.size()/2;

arr.add(n, e); \\ Insert element in the middle of list

arr.remove(n); \\ Removes element from the middle of list

java.util.ArrayList

  • ArrayList() - constructs an empty array list

  • ArrayList(ini initialCapacity) - constructs an empty array list with specified capacity

  • boolean add(Object obj) - appends an element at the end of array list, Always returns true

  • int size() - returns the no of elements currently stored in the array list

  • void ensureCapacity(int capacity) - ensures that the array list has the capacity to store the given number of elements without relocating its internal storage array

  • void trimToSize() - reduces the storage capacity of the array list to its current size

  • void set(int index, Object obj) - puts a value in the array list at specified index, overwriting previous element

  • Object get(index i) - gets the value stored at a specified index

  • void add(int index, Object obj) - shifts up elements to insert an element

  • void remove(int index) - removes an element and shoft down all the elements above it

Object Wrappers

    • There is a class (Integer) corresponding to the basic type e.g. int.

    • These classes are called object wrappers

    • The wrapper classes are final (can't override the toString() method)

    • You also cannot change the values you store in the object wrapper

list.add(new Double(3.14));

double x = ((Double) list.get(n)).doubleValue();

java.lang.Integer

  • int intValue() - return the value of Integer object as an int

The Class CLASS

    • The Java runtime system always maintains what is called runtime type identification on all objects

    • This information keeps track of the class to which each object belongs

    • Runtime type information is used by the virtual machine to select the correct methods to execute

    • The class that golds this information is called Class

    • The getClass() method in the Object class returns as instance of Class type

if (e.getClass() == Employee.class) ...

e.getClass().newInstance(); \\ Creates instance with default constructor

java.lang.Class

  • static Class forName(String className) - returns the Class object representing the class with name className

  • Object newInstance() - returns a new instance of this class

Design Hints for Inheritance

    • Place common operations and fields in the superclass

    • Don't use protected fields, instead protected methods are useful

    • Use inheritance to model the "is-a" relationship

    • Don't use inheritance unless all inherited methods make sense

    • Use polymorphism, not type information