CS & IT
ENGINEERING
Java With OOPs
OOPs using Java
Lecture No-05 By- Aditya sir
Recap of Previous Lecture
Topic Abstract Classes
Topic Inheritance
Constructors
Super
Topics to be Covered
Topic Java Collections
0
Polymorphism
Misc
3
Topic : What Is Polymorphism?
• Definition: Polymorphism means “one interface, many forms,” allowing the
same method call to behave differently based on context .
• Forms in Java:
○ Compile-Time (Static): Method and constructor overloading
00
○ Runtime (Dynamic): Method overriding with dynamic dispatch
• Benefits: Leads to flexible, reusable, and maintainable code by programming to
abstractions .
• Analogy: A universal remote that controls TV, DVD, and stereo—same buttons,
different behaviors.
maturate
3 4
7
addth
4 34
3
Concatenation
fine
Static Onlooding
Compile
Runtime dynamic Overriding
Topic : Compile-Time Polymorphism
• Method Overloading:
○ void print(int x) { … }
○ void print(String s) { … }
Resolved at compile time by matching parameter lists
• Constructor Overloading:
class Point {
Point() { this(0,0); }
Point(int x,int y){ … }
}
Use this(...) to chain constructors and avoid code duplication .
Topic : Compile-Time Polymorphism
• Rules:
○ Must differ in parameter count or types; return type alone cannot
distinguish overloads.
• Use Case:
○ [Link](int,int) vs [Link](double,double) for numeric utilities
Topic : Runtime Polymorphism
• Method Overriding: Subclass provides its own implementation of a superclass
method:
○ @Override
○ void speak() { … }
• Dynamic Dispatch:
○ JVM selects the override at runtime based on the actual object’s
• Requirements: Same signature, compatible (covariant) return type, and equal
or broader visibility.
• Use Case: GUI callbacks like paintComponent(Graphics g) in Swing components.
Topic : Covariant Return Types
• Definition: An overriding method may return a subtype of the overridden
method’s return type .
• Example:
○ class A { A get() { return this; } }
○ class B extends A { @Override B get() { return this; } }
• Advantage: More specific return type without casting; improves type safety .
Topic : Best Practices
• Always annotate overridden methods with @Override.
• Keep inheritance hierarchies as shallow as practical.
• Favor composition (“has-a”) over inheritance (“is-a”) when the relationship is
weak.
• Document overloaded and overridden methods to clarify behavioral
differences
• Validate inputs in each constructor and method level—even if parent does
it.
Topic : Best Practices
Example 1 – Calculator Overloading
• Problem: Design a Calculator class with overloaded add methods for two ints,
three ints, and two doubles.
• Hint: Implement add(int,int), add(int,int,int), and add(double,double).
Topic : Best Practices
• Code:
public class Example1 {
static class Calculator {
int add(int a, int b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
double add(double a, double b) { return a + b; }
}
public static void main(String[] args) {
Calculator c = new Calculator();
[Link]([Link](2, 3)); // 5
[Link]([Link](1, 2, 3)); // 6
[Link]([Link](2.5, 3.5)); // 6.0
}
}
Topic : Best Practices
• Expected Output:
5
6
6.0
Topic : Best Practices
Example 2 – Point Constructors
• Problem: Implement a Point class supporting:
○ No-arg → (0,0)
○ (x,y)
3 Constructors
○ Copy constructor Point(Point)
Print coordinates via toString(). Ifing
• Hint: Use this(...) to chain constructors.
Topic : Best Practices
• Code:
public class Example2 {
static class Point {
int x, y; Hiiiif
Point() { this(0, 0); }
Point(int x, int y) { this.x = x; this.y = y; } g
Point(Point p) { this(p.x, p.y); } this p n p
@Override public String toString() {
return "(" + x + "," + y + ")";
}
}
public static void main(String[] args) {
[Link](new Point()); // (0,0)
[Link](new Point(5, 7)); // (5,7)
[Link](new Point(new Point(3,4))); // (3,4)
}
}
Topic : Best Practices
• Expected Output:
(0,0)
(5,7)
(3,4)
Topic : Best Practices
Example 3 – Shape Drawing
• Problem: Abstract class Shape defines void draw(). Subclasses Circle and
Square override draw(). Draw each shape.
• Hint: Use an array of Shape references.
Topic : Best Practices
• Code:
public class Example3 {
static abstract class Shape {
abstract void draw();
}
static class Circle extends Shape {
@Override void draw() { [Link]("Drawing Circle"); }
}
static class Square extends Shape {
@Override void draw() { [Link]("Drawing Square"); }
}
public static void main(String[] args) {
Shape[] shapes = { new Circle(), new Square() };
for (Shape s : shapes) [Link]();
}
}
Topic : Best Practices
• Expected Output:
Drawing Circle
Drawing Square
Topic : Best Practices
Example 4 – Animal Speak
• Problem: Class Animal has void speak(). Subclasses Dog and Cat override
speak(). Demonstrate runtime binding via Animal a = new Dog();.
• Hint: Call speak() on a base reference.
Animal
Topic : Best Practices
• Code:
public class Example4 {
static class Animal {
void speak() { [Link]("Animal speaks"); }
}
static class Dog extends Animal {
@Override void speak() { [Link]("Woof"); }
}
static class Cat extends Animal {
@Override void speak() { [Link]("Meow"); }
}
public static void main(String[] args) {
Animal a1 = new Dog();
Animal a2 = new Cat();
[Link](); // Woof
[Link](); // Meow
}
}
Topic : Best Practices
• Expected Output:
Woof
Meow
Topic : Best Practices
Example 7 – Covariant Return Types
• Problem: Class A has A get().
Subclass Dog overrides to Dog get(). Print class names of returned objects.
• Hint: Leverage covariant return types (Java 5+).
Topic : Best Practices
• Code:
public class Example7 {
static class Animal {
Animal get() { return this; }
}
static class Dog extends Animal {
@Override Dog get() { return this; }
}
public static void main(String[] args) {
Animal a = new Animal();
Animal d = new Dog();
[Link]([Link]().getClass().getSimpleName());
[Link]([Link]().getClass().getSimpleName());
}
}
Topic : Best Practices
• Expected Output:
Animal
Dog
Topic : Key Takeaways
Recap:
• Static Polymorphism: (overloading) is bound at compile time
• Dynamic Polymorphism: (overriding) is bound at runtime
• Program to interfaces and favor composition for greater flexibility .
• Covariant returns: enhance type safety without casting .
• Use @Override, keep class hierarchies shallow, document polymorphic
behavior clearly.
•
THANK - YOU