Overloading
Method Overloading (Compile-Time Polymorphism)
Multiple methods with same name but different parameters.
Basic Overloading
public class Calculator {
// Different parameter types
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
// Different number of parameters
public int add(int a, int b, int c) {
return a + b + c;
}
}
Calculator calc = new Calculator();
System.out.println(calc.add(1, 2)); // 3
System.out.println(calc.add(1.5, 2.5)); // 4.0
System.out.println(calc.add(1, 2, 3)); // 6
Overloading Rules
public class Example {
// Valid - different types
public void method(int x) { }
public void method(double x) { }
// Valid - different count
public void method(int x, int y) { }
// Valid - different order
public void method(String s, int i) { }
public void method(int i, String s) { }
// INVALID - same signature
// public void method(int x) { }
// public void method(int y) { } // Same!
}
Return Type Doesn't Matter
public class Example {
public int method(int x) { return x; }
// public double method(int x) { return x; } // COMPILE ERROR!
// Return type alone cannot differentiate overloads
}
Constructor Overloading
public class Person {
String name;
int age;
public Person() { this("Unknown"); }
public Person(String name) { this(name, 0); }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Overriding
Method Overriding (Runtime Polymorphism)
Child class provides specific implementation of parent method.
Basic Overriding
public class Animal {
public void makeSound() {
System.out.println("Some sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
Animal animal = new Dog();
animal.makeSound(); // "Woof!"
animal = new Cat();
animal.makeSound(); // "Meow!"
Overriding Rules
public class Parent {
public void method() { }
}
public class Child extends Parent {
// Must have same name, parameters, return type
// Access modifier can be same or less restrictive
// Cannot throw new/broader checked exceptions
@Override // Optional but recommended
public void method() { }
// INVALID:
// private void method() { } // More restrictive
// public int method() { } // Different return type
// public void method(int x) { } // Different params (overloading)
}
@Override Annotation
public class Child extends Parent {
@Override // Helps catch errors
public void method() { }
@Override // Compiler checks if actually overriding
public void nonExistentMethod() { } // COMPILE ERROR!
}
Covariant Return Types
public class Animal {
public Animal create() {
return new Animal();
}
}
public class Dog extends Animal {
@Override
public Dog create() { // Return type is Dog (covariant)
return new Dog();
}
}
Dynamic Method Dispatch
Dynamic Method Dispatch
The JVM determines which method to call at runtime based on actual object type.
Basic Example
public class Animal {
public void makeSound() {
System.out.println("Animal sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
// Dynamic dispatch
Animal animal;
animal = new Dog();
animal.makeSound(); // "Woof!" (Dog's version)
animal = new Cat();
animal.makeSound(); // "Meow!" (Cat's version)
Array of Parent Type
Animal[] animals = { new Dog(), new Cat(), new Animal() };
for (Animal a : animals) {
a.makeSound(); // Each calls its own version
}
// Output:
// Woof!
// Meow!
// Animal sound
Method Parameters
public class Vet {
public void checkup(Animal animal) {
animal.makeSound(); // Calls actual type's method
}
}
Vet vet = new Vet();
vet.checkup(new Dog()); // "Woof!"
vet.checkup(new Cat()); // "Meow!"
Polymorphism Benefits
// Without polymorphism - lots of if/else
public void makeAnimalSound(Animal animal) {
if (animal instanceof Dog) {
((Dog) animal).makeSound();
} else if (animal instanceof Cat) {
((Cat) animal).makeSound();
}
}
// With polymorphism - clean code
public void makeAnimalSound(Animal animal) {
animal.makeSound(); // Polymorphism handles it!
}
Instanceof Operator
instanceof Operator
Checks if an object is an instance of a specific class or interface.
Basic Usage
Animal animal = new Dog();
if (animal instanceof Dog) {
System.out.println("It's a dog!");
}
if (animal instanceof Animal) {
System.out.println("It's an animal!");
}
if (animal instanceof Cat) {
System.out.println("It's a cat!"); // Not printed
}
Safe Casting
public void processAnimal(Animal animal) {
if (animal instanceof Dog) {
Dog dog = (Dog) animal; // Safe cast
dog.fetch();
}
}
// Or with pattern matching (Java 16+)
if (animal instanceof Dog dog) {
dog.fetch(); // No explicit cast needed
}
With null
Animal animal = null;
if (animal instanceof Dog) { } // false (not exception!)
// null instanceof anything is always false
Interface Checking
public class Dog implements Pet, Serializable {
// ...
}
Dog dog = new Dog();
if (dog instanceof Pet) { } // true
if (dog instanceof Serializable) { } // true
if (dog instanceof Object) { } // true (everything is Object)
When to Use
// 1. When you need type-specific behavior
public void feed(Animal animal) {
if (animal instanceof Dog) {
((Dog) animal).eatKibble();
} else {
animal.eat();
}
}
// 2. When you can't avoid casting
public void serialize(Object obj) {
if (obj instanceof Serializable) {
// Safe to cast
}
}
// 3. Prefer polymorphism over instanceof when possible
Practice Problems
Design a file system with files and directories.
Example:
Input: ls('/'), mkdir('/a'), addContentToFile('/a/b', 'content')
Output: [a]
File system with polymorphic components
Optimal Solution — O(n) time, O(n) space
Use abstract Entry class with File and Directory subclasses.
abstract class Entry {
protected String name;
abstract int getSize();
}
class File extends Entry {
private String content;
int getSize() { return content.length(); }
}
class Directory extends Entry {
private Map<String, Entry> children;
int getSize() { return children.values().stream().mapToInt(Entry::getSize).sum(); }
}Edge Cases:
- Empty directory
- Nested files
- Root path
Design shapes with area calculation using polymorphism.
Example:
Input: Circle(5).area(), Rectangle(4, 5).area()
Output: 78.54, 20
Different area calculations
Optimal Solution — O(1) time, O(1) space
Abstract Shape class with concrete subclasses.
abstract class Shape {
abstract double area();
}
class Circle extends Shape {
double radius;
double area() { return Math.PI * radius * radius; }
}
class Rectangle extends Shape {
double width, height;
double area() { return width * height; }
}Edge Cases:
- Zero dimensions
- Negative values
- Very large values
Design a payment system with different payment methods.
Example:
Input: pay(CreditCard), pay(PayPal)
Output: processed
Different payment processing
Optimal Solution — O(1) time, O(1) space
Abstract Payment class with concrete payment methods.
abstract class Payment {
abstract void process(double amount);
}
class CreditCard extends Payment {
void process(double amount) { /* process card */ }
}
class PayPal extends Payment {
void process(double amount) { /* process PayPal */ }
}Edge Cases:
- Invalid amount
- Failed payment
- Different currencies
Quiz
1. What is method overloading?
2. What is method overriding?
3. What does instanceof check?
4. When does dynamic method dispatch occur?
Flashcards
Question
What is the difference between overloading and overriding?
Click to reveal answer
Answer
Overloading: same name, different params (compile-time). Overriding: same method, different implementation (runtime).
Question
What is dynamic method dispatch?
Click to reveal answer
Answer
JVM determines which method to call at runtime based on actual object type, not reference type.
Question
What does @Override do?
Click to reveal answer
Answer
Optional annotation that tells compiler to verify the method actually overrides a parent method.
Question
What is polymorphism?
Click to reveal answer
Answer
Ability of objects to take many forms - same reference type can point to different object types.
Question
What is Polymorphism?
Click to reveal answer
Answer
Polymorphism is a key concept in Java programming.
Revision Notes
Key Takeaways
- 1.Overloading is compile-time, overriding is runtime
- 2.Dynamic dispatch enables polymorphism
- 3.instanceof checks object type
- 4.@Override prevents errors
Interview Tips
- •Know difference between overloading and overriding
- •Understand dynamic method dispatch
- •Use instanceof for type checking
- •Prefer polymorphism over type casting
Cheat Sheet
Cheat Sheet
- Overloading: same name, different params
- Overriding: same method, child implementation
- @Override: annotation for safety
- instanceof: type checking
- Dynamic dispatch: runtime method selection