A subclass inherits all the behavior and attributes of its superclass. It can then extend the behavior and attributes of its superclass. In fact, a subclass can change the behavior provided by its superclass. This is known as overriding. Overriding methods is a feature of polymorphism. In this section, you will learn about overriding methods.
When you call an instance method, Java looks for the definition of the method
in the object’s class. If it does not find it, Java looks up for the method
in its superclasses, all the way to the Object
class, until the method definition
is found. If the definition is not found, the method does not exist.
Inheritance allows you to define methods in superclasses and use them in instances of your subclasses. This helps you avoid rewriting the code in your subclasses. However, sometimes you may want to invoke a method but change its behavior which was defined in a superclass. In such cases, you can alter it. This is known as method overriding.
To override a method in a subclass you simply need to define the method in your subclass with the same signature and return type. Java determines if a method is overridden by comparing the signature of your method in the subclass and the superclass. If the signatures match, then that method is considered as overridden. When you invoke that method, the overridden version is executed instead of the one in the superclass.
Consider the following example which prints the popular lines of the characters from Friends.
class Friend {
public String getPopularLine() {
return "Unknown";
}
}
class JoeyTribbiani extends Friend {
@Override
public String getPopularLine() {
return "How you doin'?";
}
}
class ChandlerBing extends Friend {
@Override
public String getPopularLine() {
// PS: Could Chandler be more funny?
// This is the only program I have ever written laughing.
return "Until I was 25, I thought that the only response to 'I love you' was 'Oh crap!'";
}
}
class PhoebeBuffay extends Friend {
@Override
public String getPopularLine() {
// That's it. I'm off to watch Friends.
return "They don't know that we know they know we know.";
}
}
public class Friends {
public static void main(String ... arguments) {
Friend joey = new JoeyTribbiani();
System.out.println("Joey: " + joey.getPopularLine());
Friend chandler = new ChandlerBing();
System.out.println("Chandler: " + chandler.getPopularLine());
Friend phoebe = new PhoebeBuffay();
System.out.println("Phoebe: " + phoebe.getPopularLine());
}
}
When you compile this example, the compiler produces four files, one for each class. The output of the program is shown here.
Joey: How you doin'?
Chandler: Until I was 25, I thought that the only response to 'I love you' was 'Oh crap!'
Phoebe: Until I was 25, I thought that the only response to 'I love you' was 'Oh crap!'
The Friend
class defines a method called getPopularLine()
. It always
returns the string "Unknown"
.
To demonstrate method overriding, we created three other classes called
JoeyTribbiani
, ChandlerBing
and PheobeBuffay
which inherit the Friend
class. Each of these classes define the getPopularLine()
method with the same
signature and return type. Thus, they override the getPopularLine()
method in
their respective classes.
Sometimes you may misspell a method name or change the signature by accident in your subclass. Since Java does not force your subclass to override the definition of a method, you may end up creating a new method instead of overriding a method that exists in your superclass.
You always need to make sure that you have correctly overridden a method. Java
provides an annotation called Override
. With this annotation you can tell the
compiler to check if you have correctly overridden a method.
An annotation is a special interface that provides supplemental information
about your source code. They are similar to comments, except they are not ignored
by the compiler. You will learn more about interfaces and annotations in the next
chapter. Annotations start with @
. They provide information about your source
code to tools such compilers.
In the main()
method we create an instance of each of the subclasses of Friend
.
We assign the instances to variables of type Friend
. This is valid because Java
implicitly casts the instance to Friend
, because it is the superclass.
You can prevent a subclass from overriding a method. You simply need to add
the final
keyword in the method declaration. When a subclass tries to override
a final method, the compiler generates errors.
Here is an example of a final method.
final void printStatistics() {
...
}
You can cast an object to its superclass. This is known as up casting. Java can up cast your objects implicitly. In general, you can up cast whenever an “is-a-type-of” relationship exists between two classes.
In the previous example, you can cast JoeyTribbiani
to Friend
like this.
JoeyTribbiani joey = new JoeyTribbiani();
Friend friend = (JoeyTribbiani)joey;
In fact, you can leave the cast operator, because Java does it implicitly for you.
Similarly, you can cast an object to its subclass. This known as down casting.
Down casting involves a type check and can throw a ClassCastException
, if the
subclass is not a part of the instances class hierarchy.
In the Friends example, you can cast Friend
to ChandlerBing
like this.
Friend friend = new ChandlerBing();
ChandlerBing chandler = (ChandlerBing)friend;
But you cannot cast an instance of PhoebeBuffay
to ChandlerBing
like this.
Because ChandlerBing
is not a part of the PhoebeBuffay
class hierarchy.
Friend friend = new PhoebeBuffay();
ChandlerBing chandler = (ChandlerBing)friend;
Java provides a special operator called as instance of operator. It allows you to determine whether an object is an instance of the specified class.
Here is the general form the instance of operator.
object instanceof Class
Here, the object
represents the object you want to test. The instanceof operator
is actually a keyword. The Class
represents the class the object should
be an instance of.
Here is an example.
if (friend instanceof ChandlerBing) {
System.out.println("It is Chandler!");
}
else {
System.out.println("I don't know who this is. Is it Monica?");
}