Polymorphism

Overview

  • An object has only one form (the one that is given to it when constructed). 
  • However, a variable is polymorphic because it can refer to objects of different forms. 
  • Java permits you to refer to an object with a variable that is one of the parent class type. 
		// polymorphism
		Shape s = new Rectangle(2, 2, "polyshape");
		System.out.println(s.getDetails());
  • Which getDetails method will be invoked here? From Shape or Rectangle class? 
  • This is the aspect of polymorphism, which is an important feature of object-oriented languages. The behaviour is not determined by the compile time type of the variable, instead it refers to during runtime. 
  • In the above codes, the getDetails method executed is from the object’s real type, the Rectangle class. 

Why Override Methods?

  • As stated earlier, overridden methods allow Java to support run-time polymorphism. 
  • Polymorphism is essential to object-oriented programming for one reason: it allows a general class to specify methods that will be common to all of its derivatives, while allowing subclasses to define the specific implementation of some or all of those methods. 
  • Overridden methods are another way that Java implements the “one interface, multiple methods” aspect of polymorphism. 

Using Abstract Methods

  • Abstract methods are those defined with abstract keyword at its method signature. 

    abstract type name(parameter-list); 
  • Abstract methods mean there is no implementation provided, that is not method body. 

    abstract void callme(); 

There are situations in which you will want to define a superclass that declares the structure of a given abstraction without providing a complete implementation of every method. That is, sometimes you will want to create a superclass that only defines a generalized form that will be shared by all of its subclasses, leaving it to each subclass to fill in the details. 

Using Abstract Classes

  • Any class that contains one or more abstract methods must also be declared abstract.  
  • To declare a class abstract, you simply use the abstract keyword in front of the class keyword at the beginning of the class declaration. 
  • There can be no objects of an abstract class. That is, an abstract class cannot be directly instantiated with the new operator. 
  • Any subclass of an abstract class must either implement all of the abstract methods in the superclass, or be declared abstract itself. 
public abstract class AbstractShape {
	private String name;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public abstract double getArea();
}
public class Circle extends AbstractShape {
	private double radius;

	public Circle(double radius) {
		this.radius = radius;
	}

	// circle needs to implement the inherited abstract methods
	@Override
	public double getArea() {
		return Math.PI + Math.pow(radius, 2);
	}
}

Using final Keyword 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. 
public abstract class AbstractShape {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public abstract double getArea();

	public final void display() {
		System.out.println("name: " + getName() + ", area: " + getArea());
	}
}

The display() method in AbstractShape is final, which means it cannot be overriden in the subclass i.e. Circle.

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. 
public final class Circle extends AbstractShape {
	private double radius;

	public Circle(double radius) {
		this.radius = radius;
	}

	// circle needs to implement the inherited abstract methods
	@Override
	public double getArea() {
		return Math.PI + Math.pow(radius, 2);
	}

}

Interfaces

  • Using the interface keyword, Java allows you to fully abstract a class’s interface from its implementation. 
  • Interfaces are syntactically like classes, but they lack instance variables, and as a rule, their methods are declared without any body. 
  • Once it is defined, any number of classes can implement an interface. 
  • Also, one class can implement any number of interfaces. 

Defining an Interface

General syntax of an interface. 

access interface name 
return-type method-name1(parameter-list); 
return-type method-name2(parameter-list); 

type final-varname1 value
type final-varname2 value

//… 

return-type method-nameN(parameter-list); 
type final-varnameN value

Implementing Interfaces

To implement an interface, include the implements clause in a class definition, and then create the methods required by the interface. 

class classname [extends superclass] [implements interface [,interface…]] { 
// class-body 

If a class implements more than one interface, the interfaces are separated with a comma. 

Using Interfaces References 

  • You can declare variables as object references that use an interface rather than a class type. 
  • Any instance of any class that implements the declared interface can be referred to by such a variable. 
  • When you call a method through one of these references, the correct version will be called based on the actual instance of the interface being referred to. 
  • The method to be executed is looked up dynamically at run time. 

Variables in Interfaces

Variables declared in an interface are constants that can be shared by multiple classes. 

public interface SharedConstants {
	int NO = 0;
	int YES = 1;
	int MAYBE = 2;
	int LATER = 3;
	int SOON = 4;
	int NEVER = 5;
}

Interfaces Can Be Extended

  • One interface can inherit another by use of the keyword extends. 
  • The syntax is the same as for inheriting classes. 
  • When a class implements an interface that inherits another interface, it must provide implementations for all methods required by the interface inheritance chain. 
interface FirstInterface {
	public void first();
}

interface SecondInterface extends FirstInterface {
	public void second();
}

// the class need to provide implementations for all inherited abstract methods
class MyClass implements SecondInterface {

	@Override
	public void first() {
		System.out.println("This is the first method");
	}

	@Override
	public void second() {
		System.out.println("This is the second method");
	}

}

Default Interface Methods

  • Since JDK 8, Java added a new capability to interface called the default method. 
  • A default method lets you define a default implementation for an interface method. 
  • A primary motivation for the default method was to provide a means by which interfaces could be expanded without breaking existing code. 
  • The declaration is preceded by the keyword default. 
public interface Vehicle {
	public void calculateFuelUsage();
	
	public default void move() {
		System.out.println("Vehicle is moving...");
	}
}
public class Car implements Vehicle {

	@Override
	public void calculateFuelUsage() {
		System.out.println("Calculating fuel usage for Car...");
	}

	// default method is inherited, no need to override
}