Method Overloading vs Method Overriding in Java: Differences, Rules, and Examples

Method Overloading vs Method Overriding in Java: Differences, Rules, and Examples


Understanding the difference between method overloading and method overriding in Java is essential for mastering polymorphism in object-oriented programming. In this beginner-friendly guide, you’ll learn what each concept means, why we use them, the rules to remember, and how to write clear examples. We’ll also answer common questions students ask and show practical use cases you can apply in projects. If you’re just starting out, you can explore more beginner topics in our Java tutorials.

Key takeaway: difference between method overloading and method overriding in Java
  • Method Overloading: same method name in the same class with different parameter lists; chosen by the compiler at compile time.
  • Method Overriding: same method signature in a subclass providing a new implementation; selected by the JVM at runtime based on the object’s actual type.

Method Overloading in Java (Compile-Time Polymorphism)

Side-by-side diagram showing the difference between method overloading and method overriding in Java
Overloading vs overriding at a glance—compile-time choices vs runtime behavior.

What is method overloading?

Method overloading in Java means having multiple methods with the same name in the same class, but with different parameter lists. This is an example of compile-time polymorphism because the Java compiler decides which method to call based on the argument types and the number of arguments at compile time.

Key rules for method overloading

  • Same method name, different parameter list (type, number, or order).
  • Return type is NOT part of the method signature. You cannot overload only by changing the return type.
  • Throws clauses don’t affect overloading.
  • Constructors can be overloaded (but not overridden).
  • Overload resolution happens at compile time using the argument types available at the call site.

Simple example: Calculator with overloaded methods

Code
class Calculator {
    int add(int a, int b) { return a + b; }
    double add(double a, double b) { return a + b; }
    int add(int a, int b, int c) { return a + b + c; }
}

class="cd-keyword cd-access">public class OverloadingDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Calculator c = new Calculator();
        System.out.println(c.add(2, 3));       // calls add(int, int)
        System.out.println(c.add(2.5, 1.5));   // calls add(double, double)
        System.out.println(c.add(1, 2, 3));    // calls add(int, int, int)
    }
}
Output
5
4.0
6

Constructor overloading example

Code
class Student {
    String name;
    int age;

    Student(String name) {
        this(name, 0); // calls the other constructor
    }

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    class="cd-keyword cd-access">public String toString() {
        return name + " (" + age + ")";
    }
}

class="cd-keyword cd-access">public class ConstructorOverloadingDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Student s1 = new Student("Asha");
        Student s2 = new Student("Ravi", 20);
        System.out.println(s1);
        System.out.println(s2);
    }
}
Output
Asha (0)
Ravi (20)

Method Overriding in Java (Runtime Polymorphism)

Call flow showing the difference between method overloading and method overriding in Java: compile-time vs runtime dispatch
How Java resolves calls: parameter-based overloads and dynamic overriding.

What is method overriding?

Method overriding in Java happens when a subclass provides its own implementation of a method that is already defined in its superclass (or interface). The overriding method must have the same name and the same parameter list (i.e., the same signature). This enables runtime polymorphism: the actual method that runs is chosen at runtime based on the object’s real type, not the reference type.

Key rules for method overriding

  • Must have the same method signature as the superclass method.
  • Use @Override to catch mistakes at compile time.
  • Access level cannot be reduced (you can make it more visible, not less).
  • Covariant return types are allowed (the overriding method can return a subtype of the original return type).
  • For checked exceptions, the overriding method can declare the same or fewer (narrower) checked exceptions.
  • Static methods are not overridden; they are hidden. Final and private instance methods cannot be overridden.

Simple example: Animal sounds

Code
class Animal {
    void speak() {
        System.out.println("Some sound");
    }
}

class Dog extends Animal {
    class="cd-annotation">@Override
    void speak() {
        System.out.println("Woof");
    }
}

class Cat extends Animal {
    class="cd-annotation">@Override
    void speak() {
        System.out.println("Meow");
    }
}

class="cd-keyword cd-access">public class OverridingDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Animal a1 = new Dog(); // reference type Animal, object type Dog
        Animal a2 = new Cat(); // reference type Animal, object type Cat
        a1.speak(); // prints ___CDPHSTR3___ (runtime decision)
        a2.speak(); // prints ___CDPHSTR4___
    }
}
Output
Woof
Meow

Covariant return types example

Code
class Document {
    Document duplicate() {
        return new Document();
    }
}

class Report extends Document {
    class="cd-annotation">@Override
    Report duplicate() { // covariant return: Report is a subclass of Document
        return new Report();
    }
}

class="cd-keyword cd-access">public class CovariantReturnDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Document d = new Report();
        Document copy = d.duplicate();
        System.out.println(copy.getClass().getSimpleName());
    }
}
Output
Report

Overriding default methods from interfaces

Since Java 8, interfaces can have default methods. A class can inherit and use them, or override them just like any other instance method. If your class implements two interfaces that provide the same default method, you must resolve the conflict by overriding the method and optionally calling a specific interface’s default with InterfaceName.super.method().

Code
interface Drawable {
    default void draw() {
        System.out.println("Drawing shape");
    }
}

class Circle implements Drawable { }

class FancyCircle extends Circle {
    class="cd-annotation">@Override
    class="cd-keyword cd-access">public void draw() {
        System.out.println("Drawing fancy circle");
    }
}

class="cd-keyword cd-access">public class DefaultMethodDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Drawable d1 = new Circle();
        Drawable d2 = new FancyCircle();
        d1.draw(); // default method
        d2.draw(); // overridden
    }
}
Output
Drawing shape
Drawing fancy circle
How a method call is resolved in Java
Compile-time selection (Overloading)
1) Call site has method name + argument types
2) Compiler checks available overloaded signatures
3) Applies rules: exact match → widening → boxing → varargs
4) Emits bytecode bound to a specific signature

Runtime dispatch (Overriding)
1) Reference type declares a method
2) Object created from subclass that overrides it
3) At runtime, JVM looks up the most specific implementation
4) Subclass method executes (dynamic dispatch)

Overloading vs Overriding: Key Differences

Here is a clear comparison to help you remember the difference between method overloading and method overriding in Java:

Aspect Method Overloading Method Overriding
Where it happens Same class (or with inheritance but typical in the same class) Between superclass and subclass (or interface and implementer)
Purpose Provide multiple ways to call a method for convenience Provide a new behavior for an inherited method
Binding time Compile time (method chosen by the compiler) Runtime (method chosen by the JVM using dynamic dispatch)
Signature Must differ by parameter list Must match the superclass method’s signature
Return type Not part of signature (cannot overload by return type alone) Can be covariant (subtype of original return type)
Access modifiers No specific restriction Cannot reduce visibility (e.g., public cannot become protected)
Exceptions No effect on overloading Checked exceptions must be same or narrower
Static/final/private Can overload static, final, or private methods freely Static methods are not overridden; final/private cannot be overridden
Constructors Can be overloaded Cannot be overridden
Polymorphism type Compile-time polymorphism Runtime polymorphism
Annotation @Override not used Use @Override to avoid mistakes

Real-world style examples

  • Overloading example: A logging utility might have log(String message), log(Exception e), and log(String format, Object... args) to handle different inputs easily.
  • Overriding example: Payment processing: a base class PaymentProcessor.process(Order) overridden by CreditCardProcessor, UpiProcessor, and WalletProcessor to implement provider-specific logic.

Common mistakes and best practices

  • Thinking return type can overload a method: It cannot. The parameter list must change.
  • Forgetting @Override: Without it, a typo can create an overload instead of an override. Always use @Override for overrides.
  • Overloading pitfalls with autoboxing/varargs: Widening beats boxing, and boxing beats varargs. Be explicit to avoid confusion.
  • Trying to override static/final/private methods: Static methods can be hidden (not overridden). Final and private methods cannot be overridden.
  • Reducing method visibility when overriding: Not allowed. You may widen visibility (e.g., protected to public), but not reduce it.
Quick checklist: choosing overloading vs overriding
  • ✅ Same behavior, different inputs needed in one class? Overload with distinct parameter lists.
  • ✅ Need specialized behavior for a subclass? Override with the same signature and use @Override.
  • ✅ Prefer clarity: avoid ambiguous overloads with autoboxing/varargs; add explicit types.
  • ❌ Don’t try to overload by only changing the return type.
  • ❌ Don’t reduce visibility when overriding (e.g., public → protected).
  • ❌ Don’t “override” static/final/private methods; static can only be hidden, final/private cannot be changed.

Autoboxing vs widening overloading pitfall

Code
class OverloadPitfall {
    void m(Integer x) { System.out.println("Integer"); }
    void m(long x) { System.out.println("long"); }

    class="cd-keyword cd-access">public static void main(String[] args) {
        new OverloadPitfall().m(5); // int literal: chooses widening to long, not boxing to Integer
    }
}
Output
long

Examples of overloading and overriding in Java together

This small program shows both concepts at once: multiple print methods (overloading) and a subclass changing how one of them behaves (overriding).

Code
class Printer {
    void print(String s) { System.out.println("Text: " + s); }
    void print(int n) { System.out.println("Number: " + n); }
    void print(Object o) { System.out.println("Object: " + o); }
}

class ColorPrinter extends Printer {
    class="cd-annotation">@Override
    void print(String s) { System.out.println("Color text: " + s); }
}

class="cd-keyword cd-access">public class OverloadOverrideTogether {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Printer p1 = new Printer();
        Printer p2 = new ColorPrinter();

        p1.print("Hello");
        p1.print(10);

        // Overriding at runtime
        p2.print("Hello");

        // Overloading chosen at compile time
        p2.print(10);

        // Overloading with reference type Object
        Object obj = "Hi";
        p2.print(obj);
    }
}
Output
Text: Hello
Number: 10
Color text: Hello
Number: 10
Object: Hi

Compile time vs runtime polymorphism in Java

Method overloading is compile-time polymorphism: the compiler uses the declared types of arguments to pick the best-matching method signature. Method overriding is runtime polymorphism: the JVM uses the actual object type at runtime to dispatch the call. This is why an Animal reference can call Dog’s speak() when it points to a Dog object.

FAQ

What is the difference between method overloading and method overriding in Java?

Overloading uses the same method name in the same class with different parameter lists, and the compiler decides which to call. Overriding uses the same method signature in a subclass to replace the superclass behavior, and the JVM decides which implementation to run at runtime.

Which one is compile time and which is runtime in Java: overloading or overriding?

Overloading is compile-time polymorphism. Overriding is runtime polymorphism (dynamic dispatch).

Can we override a static method in Java?

No. Static methods are resolved at compile time and can only be hidden, not overridden. Final and private instance methods also cannot be overridden.

Why do we use method overloading and method overriding?

  • Overloading: convenience and readability by providing multiple ways to call a method with different parameters.
  • Overriding: specialization and flexibility by changing inherited behavior in subclasses.

How do you write simple examples of overloading and overriding in Java?

Overloading: write multiple add methods with different parameter types. Overriding: subclass Animal with Dog and override speak(). See the examples above for complete code and outputs.

Summary

If you remember just one line: overloading changes the parameter list (chosen at compile time), while overriding changes the implementation in a subclass (chosen at runtime). Use @Override, avoid relying on return type for overloading, and be cautious with autoboxing and varargs. These concepts unlock powerful patterns in object-oriented design and are the foundation for polymorphism in Java for beginners and beyond.

Sources / Further reading

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted