You are on page 1of 5

CSCI 1302: Computer Science II Spring 2020

Overriding Methods
Overloading vs. Overriding
In method overloading, we wrote variations of a method, passing different arguments to each. For example:

1 public static double computeAvg(int x, int y){
2 return (x + y) / 2.0;
3 }
4
5 public static double computeAvg(int x, int y, int z){
6 return (x + y + z) / 3.0;
7 }
8
9 public static double computeAvg(double x, double y){
10 return (x + y) / 2.0;
11 }


These three methods have the same name, computeAvg, but the number of the parameters is different (the first
has 2, the second has 3) or the data type of the parameters is different (the first and second have int parameters,
while the third has double).

In inheritance, we may need a variation of a superclass in our subclasses to make it more specialized. For
example, if we had the following Pet class:

1 public class Pet{
2 public void speak(){
3 System.out.println("Hello.");
4 }
5 public void exercise(){
6 System.out.println("Doing some activity");
7 }
8 }


and we had two subclasses, Dog and Fish, they would exercise differently, right? It wouldn’t make sense,
though, to make methods in each class with different names, it’s still exercise, it’s just implemented differently by
the different subclass objects, so we should just override it.

An overridden method, unlike an overloaded one, MUST have the same name AND the same number and/or
type of parameters. Consider the Dog and Fish classes below.

-1-

1 public class Dog extends Pet{
2 public void exercise(){
3 System.out.println("My owner is taking me for a walk!");
4 }
5 }



1 public class Fish extends Pet{
2 public void exercise(){
3 System.out.println("Swimming around in my bowl!");
4 }
5 }


Notice that both methods are named exercise and that neither has a parameter, just like the one in the Pet
superclass, thereby overriding the method in the superclass. Note that method overriding can only occur during
inheritance.

If a subclass overrides a superclass method, when doing that method call, the subclass version is used, otherwise,
the superclass’s version is used. Here’s an example.

1 public class OverridingDemo{
2 public static void main(String[] args){
3 Dog d = new Dog();
4 Fish f = new Fish();
5 d.speak();
6 d.exercise();
7 f.speak();
8 f.exercise();
9 }
10 }


Here’s the output:

Hello
My owner is taking me for a walk!
Hello
Swimming around in my bowl!

Because neither Dog nor Fish have a speak method, the one from the Pet class is executed (lines 5 and 7),
but because Fish and Dog have overridden the method, their versions of the exercise method are executed
rather than the one written in Pet. This means that the JVM checks the subclass first to see if it implemented a
version of the method, if not, the one in the superclass is executed.

-2-
The Object Class
Every class in Java without an extends clause, automatically inherits from the Object class. That means that
it is, directly or indirectly, the superclass of every class in Java. So what does that mean exactly?

The Object class has some general methods (some that you’ve seen before!) that, because every class inherits
from Object, every class we write has access to, to use, or to override:

toString(): returns a string representation of the object. returns a String


equals(Object obj): indicates whether some other object is equal to this one. returns a boolean
getClass(): returns the runtime class of this Object

Remember the toString method that we’ve been writing for our classes so that when they’re passed as an
argument to print statements, the object can be displayed as a string rather than what appears to be gibberish?

What we’ve actually been doing is overriding the toString method from the Object class, so now instead of
printing out the name of the class an @ symbol and a hash code like it says to do in the Object class, we’re
equipping our classes with their own version so that the string representation is more meaningful to the class.

We’ve also been “overriding” the equals method, but we’ve actually not been doing it properly.

First of all, remember that overriding means that the name of the method and the data type and number of its
parameters must be the same. The parameter for our equals methods have always been the same as the class
where we wrote the method, but according to the equals method in the Object class, the parameter should
be of type Object. That is:

public boolean equals(Object obj)

Next, we should also check to see if the argument is null and return false in that case.

If the argument passed isn’t the same class as our object, we should probably also return false. This
gets a bit tricky when dealing with subclasses, but we’ll discuss this later. That’s where the getClass method
comes in. We should check the class of the argument against the class of our object and if it isn’t the same, they
can’t be equal.

We can then continue the rest of our equals method like before, comparing the attribute values.

All that being said, here’s an example. Remember our Car class? To determine whether two Car objects were
equal, compared their make, year, model, and mpg values. Here’s that original equals method:

1 public boolean equals(Car anotherCar){
2 if(this.make.equals(anotherCar.make) && this.year == anotherCar.year &&
3 this.mpg == anotherCar.mpg && this.fuel == anotherCar.fuel){
4 return true;
5 }
6 //else{ //not necessary: if the if statement is false, we skip it and come
here
7 return false;
8 // }
9 }

-3-


Remember that this method compares the current object (this) and the argument anotherCar. If they’re the
same, then it returns true, otherwise, it returns false.

Here’s what this method should look like:



1 public boolean equals(Object anotherCar){
2 if(anotherCar == null) { return false; }
3 if(this.getClass() != anotherCar.getClass()) { return false; }
4
5 return this.make.equals(anotherCar.make) && this.year == anotherCar.year
6 && this.mpg == anotherCar.mpg && this.fuel == anotherCar.fuel;
7 }


So if anotherCar is null or if it’s class is different from the calling object, we’ll return false without checking
to see if the attribute values are the same (there’s no reason to check it at that point, right?).

There’s a problem with this though. The parameter is of type Object, not of type Car and remember what we
said: Inheritance is a one-way relationship, so every Car is an Object, but not every Object is a Car. Object
is the superclass, so it has no knowledge of the attributes in the Car class. What we need to do, then, is to tell
the compiler to treat the argument as a Car. At this point, we already know that their classes are the same, so
we know that it is a Car, we just need to assure the compiler that we can access its attributes and methods.

This means we need to typecast the Object variable into a Car. To typecast, you put the type you want to cast
it to in parentheses before the variable. See below:

1 public boolean equals(Object anotherCar){
2 if(anotherCar == null) { return false; }
3 if(this.getClass() != anotherCar.getClass()) { return false; }
4
5 Car other = (Car) anotherCar;
6
7 return this.make.equals(other.make) && this.year == other.year &&
8 this.mpg == other.mpg && this.fuel == other.fuel;
9 }


Line 5, demonstrates typecasting. anotherCar is typecasted as a Car and stored into the object named other.
This object is then compared with the calling object (line 8).

-4-
Using superclass method in overridden method
Sometimes its useful to use the superclass version of a method in the body of the overridden method.

For example, let’s say we added a toString method to our Person class.

1 public String toString(){
2 return "My name is " + name + ". I am a " + age + " year old " + gender;
3 }


This would display the following if we wrote the following statements in a driver:

1 Person bob = new Person("Bob", "Male", 19);
2 System.out.println(bob);


My name is Bob. I am a 19 year old Male

For our Student objects, we want to print out the same information PLUS student related information. We could
call getters in the toString method in the Student class, BUT, all that’s already taken care of for us in the
Person class, why not use that to our advantage.

1 public String toString(){
2 return super.toString() + "\nI am a " + classification + " in " + major;
3 }


The first part of the return statement calls the toString method from Person, then we add the Student
related things we want to return. So if we demo this in a driver like so:

1 Student stew = new Student("CS", 3.12, "Junior", "Stu", "Male", 20);
2 System.out.println(stew);


We get the following output from the print statement on line 2.

My name is Stu. I am a 20 year old Male


I am a Junior in CS

The first line should be familiar as it comes from the Person toString method.

Try this yourself with the Teacher class you wrote from the first set of notes. Write a toString method that
calls the toString method from the superclass as part of the string representation for the Teacher. Be sure
to add the Teacher related attribute as part of the return statement. Submit the updated .java file to the
corresponding dropbox

-5-

You might also like