Skip to content

Unit 13: Overloading

Learning Objectives

Students should

  • understand what is overloading.
  • understand how to create overloaded methods.

Method overloading

In the previous unit, we introduced method overriding. That is, when a subclass defines an instance method with the same method descriptor as an instance method in the parent class.

In contrast, method overloading is when we have two or more methods in the same class (or inherited from superclass) with the same name but a differing method signature1. In other words, we create an overloaded method by changing the type, order, and number of parameters of the method but keeping the method name identical.

Lets consider an add method which allows us to add two numbers, and returns the result. What if we would like to create an add method to sum up three numbers?

1
2
3
4
5
6
7
public int add(int x, int y) {
  return x + y;
}

public int add(int x, int y, int z) {
  return x + y + z;
}

In the example above, the methods add(int, int) and add(int, int, int) are overloaded. They have the same name but a different number of parameters. We can see that this allows us to write methods to handle differing inputs.

Now lets consider our Circle class again. Our Circle::contains(Point) method allows us to check if a Point is within the radius of the current instance of the Circle. We would like to create a new method Circle::contains(double, double) which will allow us to check if an x and y coordinate (another valid representation of a point) is within our circle.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Circle {
  private Point c;   
  private double r;  

  public Circle(Point c, double r) {
    this.c = c;
    this.r = r;
  }

  public double getArea() {
    return Math.PI * this.r * this.r;
  }

  public boolean contains(Point p) {
    return false;
    // TODO: Left as an exercise
  }

  public boolean contains(double x, double y) {
    return false;
    // TODO: Left as an exercise
  }

  @Override
  public String toString() {
    return "{ center: " + this.c + ", radius: " + this.r + " }";
  }
}

In the above example, Circle::contains(Point) and Circle::contains(double, double) are overloaded methods.

Recall that overloading requires changing the order, number, and/or type of parameters and says nothing about the names of the parameters. Consider the example below, where we have two contains methods in which we swap parameter names.

1
2
3
4
5
6
7
8
9
  public boolean contains(double x, double y) {
    return false;
    // TODO: Left as an exercise
  }

  public boolean contains(double y, double x) {
    return true;
    // TODO: Left as an exercise
  }

These two methods have the same method signature, and therefore contains(double, double) and contains(double, double) are not distinct methods. They are not overloaded, and therefore this above example will not compile.

1
2
3
4
_.java:_: error: method contains(double,double) is already defined in class Circle
  public boolean contains(double y, double x) {
                 ^
1 error

As it is also a method, it is possible to overload the class constructor as well. As in the example below, we can see an overloaded constructor which gives us a handy way to instantiate a Circle object that is the unit circle centred at origin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Circle {
  private Point c; 
  private double r;

  public Circle(Point c, double r) {
    this.c = c;
    this.r = r;
  }

  // Overloaded constructor
  public Circle() {
    this.c = new Point(0, 0);
    this.r = 1;
  }
    :
}
1
2
3
4
// c1 points to a new Circle object with a centre (1, 1) and a radius of 2
Circle c1 = new Circle(new Point(1, 1), 2); 
// c2 points to a new Circle object with a centre (0, 0) and a radius of 1
Circle c2 = new Circle();

It is also possible to overload static class methods in the same way as instance methods. In the next unit, we will see how Java chooses which method implementation to execute when a method is invoked.

Overriding vs Overloading

Properties Overriding Overloading
Same method name
Same method signature
In the same class
In the subclass

Note that the last point is quite subtle. This is because the subclass inherits all the method from the superclass. As such, in the following example, we still have overloading.

1
2
3
4
5
6
7
class T {
  void foo(double x) { }
}

class S extends T {
  void foo(int x, int y) { }
}

Chaining Constructor

If we look at the call to overloaded constructor new Circle(), it is equivalent to new Circle(new Point(0, 0), 1). Recap the spirit of abstraction

"Each significant piece of functionality in a program should be implemented in just one place in the source code. Where similar functions are carried out by distinct pieces of code, it is generally beneficial to combine them into one by abstracting out the varying parts."

In the spirit of abstraction, we may want our overloaded constructor Circle::Circle() to invoke our original constructor Circle::Circle(Point, double). That way, any changes will have to be made in only one place. This can be achieved by invoking this(..) as the first line on the constructor. So, our Circle class can be written as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Circle {
  private Point c;
  private double r;

  public Circle(Point c, double r) {
    this.c = c;
    this.r = r;
  }

  // Overloaded constructor with a call to this(..)
  public Circle() {
    this(new Point(0, 0), 1);
  }
    :
}

If there are more constructors, we can have more chaining. We may want to chain from the "simpler" constructor to the more "complex" constructor. Consider adding another overloaded constructor that allows specifying a radius but will always be centred at origin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Circle {
  private Point c;
  private double r;

  public Circle(Point c, double r) {
    this.c = c;
    this.r = r;
  }

  // Overloaded constructor 1
  public Circle(double r) {
    this(new Point(0, 0), r); // chained to Circle::Circle(Point, double)
  }

  // Overloaded constructor 2
  public Circle() {
    this(1); // chained to Circle::Circle(double)
  }
    :
}

Remember how we mentioned that the call to super(..) (if any) in the constructor must be the first line in the constructor? The call to this(..) (if any) must also be the first line in the constructor. Therefore, you cannot have both call to super(..) and call to this(..). Which also means that if there is a call to this(..) default constructor is also not automatically added.


  1. Note that this is not the same as the method descriptor. You can not overload a method by changing the return type.