CodeGym /Courses /JAVA 25 SELF /Method overriding: how it differs from overloading

Method overriding: how it differs from overloading

JAVA 25 SELF
Level 18 , Lesson 2
Available

1. Method overriding

Overriding (overriding) is the ability in a subclass to write its own version of a method that already exists in the parent class. Thanks to this, true polymorphism works at run time (run-time).

In simple terms:
If you have a base class with a method and you want a subclass to perform that method in its own way, you simply declare a method with the same signature in the subclass. When the method is called through a reference of the base type, the version from the actual type of the object will be invoked.

Real-world example.
Imagine you have a team of animals and you ask each one to “make a sound.” For all of them the command is makeSound(), but a dog barks, a cat meows, and a cow moos. In code it looks like a call to the same method, but the result differs — that’s the magic of overriding!

Overriding syntax

Basic example

class Animal {
    void makeSound() {
        System.out.println("An animal makes some kind of sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark!");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Meow!");
    }
}

Here, the Animal class defines the makeSound() method. The subclasses Dog and Cat override this method, providing their own implementation.

The @Override annotation

In Java it’s recommended (and a good habit) to mark overridden methods with the @Override annotation:

@Override
void makeSound() { ... }

This is not required for the code to work, but:

  • The compiler will check that you are actually overriding a method (and not accidentally misspelling its name or parameters).
  • It improves code readability — other developers can immediately see that this method overrides a parent method.

Calling an overridden method

Animal myDog = new Dog();
myDog.makeSound(); // Prints: Bark!

Although the variable is of type Animal, it actually points to a Dog object, and the method from the Dog class is called. This is dynamic (late) binding.

2. Difference between overriding and overloading

Overloading

  • Within a single class (or in a hierarchy, but always “side by side”).
  • Methods have the same name but different parameters (type, count, order).
  • Method selection happens at compile time.
void print(int x) { ... }
void print(String s) { ... }

Overriding

  • In different classes: a method is declared in a superclass and overridden in a subclass.
  • Methods have the same name and signature (parameters and return type).
  • Method selection happens at run time, based on the actual type of the object.

Comparison table

Overloading Overriding
Where Within a single class In a superclass and a subclass
Method name Same Same
Parameters Different Same
Return type May differ Must match or be a subtype
When selected Compile time Run time
Annotation Not required @Override (recommended)

3. Rules for method overriding

Overriding is powerful, but it comes with strict rules. Let’s go through them one by one.

The method signature must match

  • The method name, parameter types, and order must be identical to the method in the superclass.
  • The return type must match or be covariant (that is, a subtype of the parent method’s return type).

Example with a covariant return type:

class Animal {
    Animal reproduce() { return new Animal(); }
}
class Cat extends Animal {
    @Override
    Cat reproduce() { return new Cat(); } // OK! Cat is a subtype of Animal
}

Access modifier

The access modifier of an overridden method cannot be more restrictive than the one in the superclass. If the method in the parent is public, then in the subclass it must remain public. You cannot make it less accessible (protected or private).

Example:

class Parent {
    public void greet() { }
}
class Child extends Parent {
    // void greet() { } // Error! The default (package-private) modifier is less accessible than public
    @Override
    public void greet() { } // OK
}

Exceptions

  • An overridden method cannot throw new checked exceptions that are not declared in the base method.
  • You may throw fewer or the same exceptions.

Example:

class Parent {
    void doWork() throws IOException { }
}
class Child extends Parent {
    @Override
    void doWork() throws FileNotFoundException { } // OK, FileNotFoundException is a subtype of IOException
    // void doWork() throws SQLException { } // Error! SQLException is not declared in the parent
}

Static methods are not overridden

Static methods can be hidden (hidden) but not overridden. If you declare a static method with the same signature in a subclass, this is not overriding! It will be method hiding, not polymorphism.

class Animal {
    static void info() { System.out.println("Animal"); }
}
class Dog extends Animal {
    static void info() { System.out.println("Dog"); }
}

Calling Dog.info() will print "Dog", but if you call it through a variable of type Animal, the Animal.info() method will be invoked. This is not polymorphism!

final methods cannot be overridden

If a method in the superclass is declared as final, attempting to override it will result in a compilation error.

class Animal {
    final void sleep() { }
}
class Dog extends Animal {
    // @Override
    // void sleep() { } // Error! You cannot override a final method
}

4. Practical examples

Let’s look at how overriding works in practice and how it differs from overloading.

Example 1: The Shape class and its descendants

class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

class Rectangle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a rectangle");
    }
}

Using polymorphism:

public class Main {
    public static void main(String[] args) {
        Shape s1 = new Circle();
        Shape s2 = new Rectangle();
        s1.draw(); // Drawing a circle
        s2.draw(); // Drawing a rectangle
    }
}

Although the variables are declared as Shape, the method of the class to which the object actually belongs is called.

Example 2: Difference from overloading

class Printer {
    void print(String s) {
        System.out.println("String: " + s);
    }

    void print(int n) {
        System.out.println("Number: " + n);
    }
}

Here both methods are named print, but they have different parameters — this is overloading, not overriding.

5. Overriding and calling the parent method (super)

Sometimes in an overridden method you want to first execute the parent’s logic and then add your own. Use the super keyword for this.

class Animal {
    void makeSound() {
        System.out.println("The animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        super.makeSound(); // Call the parent method
        System.out.println("Bark!");
    }
}

The call new Dog().makeSound() will output:

The animal makes a sound
Bark!

How dynamic binding (late binding) works

When you call a method through a reference of a base type, Java at run time looks at which actual object this reference points to and calls the version of the method that is defined in that object’s class.

Animal a = new Cat();
a.makeSound(); // Will call Cat.makeSound(), not Animal.makeSound()

This is the foundation of polymorphism in Java.

6. How this relates to your application

In our training application (for example, an employee management system) you can create a base class Employee with a work() method, and the subclasses Manager and Developer can implement this method in their own way:

class Employee {
    void work() {
        System.out.println("The employee is working");
    }
}

class Manager extends Employee {
    @Override
    void work() {
        System.out.println("The manager leads");
    }
}

class Developer extends Employee {
    @Override
    void work() {
        System.out.println("The developer writes code");
    }
}

Now you can store all employees in a single array or list:

Employee[] employees = {new Manager(), new Developer(), new Developer()};
for (Employee e : employees) {
    e.work(); // Each produces its own output!
}

7. Common mistakes when overriding methods

Mistake #1: a typo in the method name or parameters. If you accidentally make a mistake in the method name or its parameters, you are not overriding the method — you are creating a new one. As a result, polymorphism won’t work. That’s why you should always use the @Override annotation — the compiler will immediately catch it.

Mistake #2: a more restrictive access modifier. If the method in the parent is public and you declare it as protected or without a modifier in the child class, you will get a compilation error.

Mistake #3: trying to override a static or final method. Static methods are not overridden, and final methods cannot be overridden at all. If you try — the compiler will stop you.

Mistake #4: changing the return type to an incompatible one. If the return type of the method in the subclass does not match the type in the superclass (and is not its subtype), the compiler will not allow you to override the method.

Mistake #5: adding new checked exceptions. An overridden method cannot throw new checked exceptions that are not in the base method’s declaration. If you do this — the compiler will produce an error.

Mistake #6: forgetting about super. If in an overridden method you want to preserve part of the parent’s behavior, don’t forget to explicitly call super.methodName(). Java won’t do this for you.

Now you know how method overriding works, how it differs from overloading, and how it enables polymorphism in Java. In the next lecture we’ll look at how to apply polymorphism in practice — with collections, arrays, and real-world tasks!

1
Task
JAVA 25 SELF, level 18, lesson 2
Locked
Zoo Voices: Overriding a Method in a Subclass
Zoo Voices: Overriding a Method in a Subclass
1
Task
JAVA 25 SELF, level 18, lesson 2
Locked
Printing Magic: Difference Between Overriding and Overloading
Printing Magic: Difference Between Overriding and Overloading
1
Task
JAVA 25 SELF, level 18, lesson 2
Locked
The Art of Drawing: Using the @Override Annotation
The Art of Drawing: Using the @Override Annotation
1
Task
JAVA 25 SELF, level 18, lesson 2
Locked
Pet's Musical Performance: Calling a Parent Method with super
Pet's Musical Performance: Calling a Parent Method with super
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION