KaiquanMah's picture
FIND LATEST IMPLEMENTED METHOD vs instanceof vs getClass [OBJECT TYPE]
5ecac4f verified
Let's also examine a situation where a METHOD is OVERRIDDEN in a subclass.
In the class "Lorry", the method getCapacity has been IMPLEMENTED AGAIN:
class Truck {
private int capacity;
public Truck(int capacity) {
this.capacity = capacity;
}
public int getCapacity() {
return this.capacity;
}
}
class Lorry extends Truck {
private int trailerCapacity;
public Lorry(int capacity, int trailerCapacity) {
super(capacity);
this.trailerCapacity = trailerCapacity;
}
// HERE
@Override
public int getCapacity() {
return super.getCapacity() + trailerCapacity;
}
}
Let's create a new object of type "Lorry", and save the reference to a "Truck"-type variable.
The type of the variable defines the operations that can be used:
thus, we can only call methods defined in the "Truck" class.
So let's call the "getCapacity" method, which is defined in the "Truck" class and overridden in the "Lorry" class.
public class LorryTest {
public static void main(String[] args) {
//INITIALISE 'Lorry' object as a 'Truck' / superclass
Truck vehicle = new Lorry(10, 20);
System.out.println("Capacity: " + vehicle.getCapacity());
}
}
The program outputs
Capacity: 30
From this example, we notice that the method call is directed to the implementation given in the Lorry class, even though the type of the variable is Truck.
As a general rule,
- The VARIABLE TYPE DETERMINES the AVAILABLE OPERATIONS / METHODS
- The OBJECT TYPE determines the IMPLEMENTATIONS used by the METHODS
This is called dynamic binding: Java always looks for the LATEST IMPLEMENTATION of each METHOD.
https://docs [dot] google [dot] com/presentation/d/e/2PACX-1vTpe_7VNECaErEVyCbdD2Ud_CcEaS7sDoG7YD5ic--v34mX0QCzEZRQ-q-ENqkjTI6wiGT-Kh0rHNPl/embed?start=false&loop=false&slide=id.p
==========================================
Note that dynamic binding works in the same way also with internal calls of an object.
Let's look at a situation where the class 'DetectiveNovel' inherits from the class 'Book'.
In the "DetectiveNovel" class, the 'getTitle' method is overridden, but not the toString method.
class Book{
public String getTitle(){
return "book - ";
}
public String getPublisher(){
return "publisher";
}
public String toString(){
return getTitle() + getPublisher();
}
}
class DetectiveNovel extends Book {
@Override
public String getTitle() {
return "detective novel - ";
}
}
When the "toString" method is called for a "DetectiveNovel"-type object,
it always uses the "DetectiveNovel" class implementation for the "getTitle" method:
public class DetectiveNovelTest {
public static void main(String[] args) {
Book book = new DetectiveNovel();
System.out.println(book.toString());
}
}
// 'Book' toString()
// IMPLEMENTs getTitle() + getPublisher()
// ie 'DetectiveNovel'/OVERRIDDEN getTitle() + 'Book'/ORIGINAL getPublisher()
The program outputs:
detective novel - publisher
==========================================
Determining the Type of an Object
As the TYPE of an OBJECT DETERMINES the outcome of a METHOD CALL in some situations,
we need to be able to determine the type.
This is done, for instance, with the operator 'instanceof'.
The operator returns the value true, if the given object is of the given class type, i.e.
A instanceof B
obj1 instanceof Class1
variable1 instanceof Class1
returns the value true if A's type is B.
An example clarifies the situation:
public static void main(String[] args) {
Person ollie = new Student("Oliver", "12345", 123);
System.out.println(ollie instanceof Student);
System.out.println(ollie instanceof Person);
System.out.println(ollie instanceof Object);
System.out.println(ollie instanceof Teacher);
}
The Program outputs:
true
true
true
false
So, a "Student" type is both a "Student", "Person" and "Object".
In fact, the statement
A instanceof Object
is true for all Java objects, as "Object" is the superclass of all classes.
If there is a need TO DETERMINE the "ACTUAL" TYPE of an OBJECT and the type of the superclass is not sufficient,
we can use the method "getClass":
public static void main(String[] args) {
Person oliver = new Student("Oliver", "12345", 123);
System.out.println("Oliver is a Person: " + (oliver instanceof Person));
System.out.println("Oliveris a Person: " + (oliver.getClass() == Person.class));
System.out.println("Oliver is a Student: " + (oliver instanceof Student));
System.out.println("Oliver is a Student: " + (oliver.getClass() == Student.class));
}
Ohjelma tulostaa:
Oliver is a Person: true // 'Student' object type is a subclass of 'Person'
Oliver is a Person: false // 'Student' object type was not initialised as a 'Person' class
Oliver is a Student: true // 'Student' object type
Oliver is a Student: true // 'Student' object type was initialised as a 'Student' class
====================
A typical example is the "equals" method,
where it is determined whether an object is of the same type as the object being compared
- see an example by generating the "equals" method in Eclipse!
Let's consider an example of a method that receives a list of "Person"-class type objects
and prints information about each object,
whether it is a "Person", "Student" or "Teacher" object:
// VARIABLE TYPE = 'Person'
// OBJECT TYPE => depends on HOW OBJECTS WERE INITIALISED
public static void whatType(ArrayList<Person> people) {
for (Person person : people) {
if (person.getClass() == Person.class) {
System.out.println("This is a person!");
}
else if (person.getClass() == Student.class) {
System.out.println("This is a student!");
}
else if (person.getClass() == Teacher.class) {
System.out.println("This is a teacher!");
}
}
}