8 Module 8 — Chapter 13

🛠 Abstract Classes

Incomplete by design — powerful by purpose
In Java, if a concept is too general to represent a specific real-world object, we must prevent anyone from creating an instance of it. The abstract keyword is how Java enforces this — making the compiler your guardian against logical errors.
✅ Encapsulation
✅ Abstraction
✅ Inheritance
✅ Polymorphism
🛠 Abstract Classes (today)

! Critical Distinction — Abstract Class ≠ Abstraction

🚨 Read This Before Anything Else!

Today we study abstract classes — a Java keyword and mechanism.
This is NOT the same as the 2nd pillar of OOP called "Abstraction".

Many students confuse these two. Let us be absolutely clear:

Abstraction (2nd OOP Pillar)
  • An OOP design principle
  • Hiding internal details from users
  • Showing only what is necessary
  • Example: you drive a car without knowing its engine internals
  • Achieved by interfaces, encapsulation, abstract classes
Abstract Class (Java Mechanism)
  • A Java language feature (abstract keyword)
  • A class that cannot be instantiated
  • May contain abstract methods (no body)
  • Must be subclassed to be used
  • Today's topic!
💡 One Sentence Summary

Abstraction is the concept (what we want to achieve). Abstract class is one tool in Java that helps us achieve it — but they are not the same thing.

1 What Does "Abstract" Mean?

Before we write a single line of code, we must understand the word itself. Programming is built on real-world thinking, so let us start with the English meaning.

🕐
ABSTRACT idea
Vague • General • Incomplete
Not tied to one specific thing

"Shape" — you picture something,
but which shape exactly?


"Animal" — exists, but which one?
"Vehicle" — but what kind?
📋
CONCRETE idea
Specific • Clear • Complete
Represents one definite thing

"Circle" — no doubt, you know it!

"Cat" — specific, exists in reality
"Car" — clear, identifiable object

🦌 Animal Hierarchy:

Animal
Mammal
Camel
Hashi (baby camel)
← More abstract (cannot be a specific object) More concrete (specific, real object) →
🔑 The Key Insight

In the real world, the definition of an object (from OOP) is: an entity that represents a specific, identifiable thing in the real world. An abstract concept does not satisfy this definition — you cannot point at a "shape" sitting on a table. You can only point at a circle, a rectangle, or a triangle.

2 Class Discussion — Discovering Abstract Classes

Story 1 🖌 The Professor and the Shape

🏫 In the classroom...

👨‍🏫 The Professor says:
My students — please take out a paper and draw a shape.
👤 A student draws a circle and shows it.
(proudly shows a circle)
👨‍🏫 The Professor smiles and says:
I did not say draw a circle. I said draw a shape.
The student pauses...
Yes, a circle IS a shape — absolutely correct! But I said "shape", not "circle". So which shape did I mean? A square? A triangle? You cannot know, because "shape" does not specify a particular object!
👤 Another student:
Okay doctor, what if you asked me to color a shape?
👨‍🏫 The Professor:
Exactly the same problem! You cannot color a "shape" — you can color a circle, or a rectangle. The concept "shape" is too general.

Conclusion: "Shape" does not represent a specific object. It is an abstract concept.

Story 2 🏪 The Farm and the Animal

🐑
Sheep
🐐
Goat
🐶
Dog
🐱
Cat
"Animal"

🏫 On a farm with sheep, goat, dog, cat...

👨‍🏫 The Professor:
We have guests coming. Please bring me an animal for our hospitality.
👤 Student (brings a goat):
Here you are, professor!
👨‍🏫 The Professor:
Good — but notice what you did. I said "animal" and you brought a specific one — a goat. You had to choose something specific, because you cannot hand a guest just an "animal". You must bring a goat or a sheep.

This is the key: "animal" does not represent a specific object in reality. It is an abstract idea. The concrete things are: goat, sheep — each is specific and identifiable.
🌟 The Insight:
The definition of an OOP object is: an entity with identity that represents a specific, identifiable thing in the real world — no doubt about what it is.

"Animal" fails this test → abstract.
"Goat" passes it → concrete.
"Shape" fails this test → abstract.
"Circle" passes it → concrete.

Therefore: it is not logical to create an object of "Animal" or "Shape".

3 "Then Why Have Shape at All?"

If we agree we cannot create an object of Shape — a smart student will raise their hand:

👤 Student asks:
Doctor, if we cannot create an object of Shape, then why do we have it at all? Why not just define Circle, Rectangle, and Triangle directly?
👨‍🏫 The Professor:
Excellent question — I love it! There are two powerful reasons:
Reason 1 — Inheritance

Circle, Rectangle, and Triangle all share common attributes (e.g., color) and common behaviors (e.g., getColor()). Without Shape, we would repeat this code in every subclass. Inheritance eliminates redundancy.

🔄
Reason 2 — Polymorphism

To treat Circle, Rectangle, and Triangle polymorphically (one array, one loop, one method), they must be related by an IS-A relationship. Shape provides that common ancestor. No Shape = no polymorphism between them.

📌 The Answer in One Sentence

We keep Shape because we need it for inheritance (shared attributes/methods) and polymorphism (IS-A relationship) — even though we never create a Shape object directly.

4 The abstract Class — Syntax & Meaning

We agree: it is not logical to create an object of Shape. But programmatically, Java does not automatically prevent it — unless we tell it to. The solution: declare the class as abstract.

abstract class Shape { ... }
❌ Compile Error — Cannot Instantiate
Shape s = new Shape();
// ERROR! Shape is abstract
✅ Correct — Use a Subclass
Shape s = new Circle(...);
// OK! Circle IS-A Shape
🛠 Abstract Class
  • Incomplete — has at least one method without a body
  • Cannot be instantiated (new Shape() = error)
  • Must be subclassed
  • Represents a concept too general to be a real object
✅ Concrete Class
  • Complete / fully built — all methods have implementations
  • Can be instantiated (new Circle() = OK)
  • Represents a specific, real-world object
  • A class with no abstract keyword is concrete
📌 Definition — Abstract Class

An abstract class is a class declared with the abstract keyword. It is incomplete — it cannot be instantiated directly. But it can have concrete attributes (like color) and concrete methods (like getColor()) — the "incomplete" part refers only to the abstract methods that have no body yet. Those attributes and concrete methods are fully inherited by every subclass.

5 Abstract Methods — Incomplete by Design

The Problem Can getArea() have a generic implementation?

👨‍🏫 The Professor:
Now, our Shape has a method called getArea(). My students — can anyone give me a single formula for the area that works for ALL shapes?
👤 Students (all at once):
No, doctor! Impossible! Each shape has a completely different formula:
  • Circle: π × r²
  • Rectangle: width × height
  • Triangle: Heron's formula
There is no single formula for ALL shapes!
👨‍🏫 The Professor:
Then someone might say — "let's just remove getArea() from Shape and put it only in each subclass." But wait — what problem does this create?
👤 Excellent Student:
Doctor, if getArea() is not in Shape, then when we treat shapes polymorphically, we cannot call s.getArea() on a Shape reference — the compiler will reject it! Polymorphism works through the reference type (Shape), so the method must be declared there.
👨‍🏫 The Professor:
Perfect! And there is another risk — what if a developer creates a new subclass Pentagon extends Shape and forgets to implement getArea()? If getArea() is in Shape with a body (e.g., return 0;), Pentagon silently inherits the wrong implementation and there is no warning!

The solution: declare getArea() as ABSTRACT in Shape.

Syntax Abstract Method Declaration

🛠 Abstract Method — Header Only, No Body
abstract class Shape { private String color; public Shape(String color) { this.color = color; } public String getColor() { return color; } // normal method ✓ // ── Abstract methods: header only, NO body ───────────────────── public abstract double getArea(); // no { } ← that is the point! public abstract double getPerimeter(); // no { } ← incomplete on purpose // ── A normal (concrete) method CAN exist in abstract class ────── public String toString() { return "Shape[color=" + color + ", area=" + getArea() + "]"; } }
💡 What abstract method means
  • Only the signature/header is declared
  • No body — no { }
  • Ends with a semicolon ;
  • Forces subclasses to provide the implementation
  • Guarantees the behavior EXISTS in all subclasses
⚠ The Two Guarantees
  • Guarantee 1: Every concrete subclass WILL have getArea()
  • Guarantee 2: It WILL have a real implementation (not a default return 0)
  • The compiler enforces both — no developer can forget!

Example Complete Shape Hierarchy

📄 Shape Hierarchy — Circle, Rectangle, Triangle
abstract class Shape { private String color; public Shape(String color) { this.color = color; } public String getColor() { return color; } public abstract double getArea(); public abstract double getPerimeter(); public String toString() { return String.format("[%s | color=%s | area=%.2f]", getClass().getSimpleName(), color, getArea()); } } class Circle extends Shape { private double radius; public Circle(String color, double radius) { super(color); this.radius = radius; } @Override public double getArea() { return Math.PI * radius * radius; } @Override public double getPerimeter() { return 2 * Math.PI * radius; } } class Rectangle extends Shape { private double width, height; public Rectangle(String color, double width, double height) { super(color); this.width = width; this.height = height; } @Override public double getArea() { return width * height; } @Override public double getPerimeter() { return 2 * (width + height); } } class Triangle extends Shape { private double a, b, c; public Triangle(String color, double a, double b, double c) { super(color); this.a = a; this.b = b; this.c = c; } @Override public double getArea() { // Heron's formula double s = (a + b + c) / 2; return Math.sqrt(s * (s-a) * (s-b) * (s-c)); } @Override public double getPerimeter() { return a + b + c; } } // ── Polymorphic usage ────────────────────────────────────────── public class TestShapes { public static void main(String[] args) { Shape[] shapes = { new Circle("Red", 5), new Rectangle("Blue", 4, 6), new Triangle("Green", 3, 4, 5) }; for (Shape s : shapes) System.out.println(s); // calls toString() → calls getArea() } }
Output — TestShapes.java
[Circle | color=Red | area=78.54] [Rectangle | color=Blue | area=24.00] [Triangle | color=Green | area=6.00]

6 The Rules of Abstract Classes

Study each rule carefully. Each one has an example to make it concrete.

1 Subclass implements ALL abstract methods → it becomes concrete and can be instantiated

If a subclass provides a @Override implementation for every abstract method it inherited, the compiler considers it complete — it becomes a normal (concrete) class and you can create objects of it.

2 Subclass does NOT implement all abstract methods → it must remain abstract

If a subclass implements some but not all abstract methods, it is still incomplete. The compiler forces it to also be declared abstract.

3 A class that contains any abstract method MUST be declared abstract

You cannot have an abstract method inside a non-abstract class. The class becomes incomplete the moment it contains an abstract method, so it must be abstract too.

4 If a non-abstract class extends an abstract class, it MUST implement ALL inherited abstract methods

Even if the developer does not plan to use a particular method — they must still implement it. The compiler enforces this with no exceptions. This is exactly what we want!

5 An abstract class CAN have zero abstract methods (all methods can be concrete)

You can declare a class abstract even if it has no abstract methods at all. This simply prevents instantiation — useful when the class is logically incomplete, even though all its methods have implementations.

📌 Why do this?

Sometimes the concept is not logical to instantiate (like Animal or Vehicle), even if all behaviors have reasonable default implementations. Making it abstract expresses this design intent clearly.

6 A subclass CAN be abstract even if its superclass is concrete

Abstractness does not flow only top-down. A subclass of a concrete class can itself be abstract. A famous real-world example: the Object class in Java is concrete — yet Shape (which extends Object) can be abstract.

7 An abstract class CAN be used as a data type (polymorphic variable, array, method parameter)

Even though you cannot create a new Shape(), you CAN declare a variable, an array, or a method parameter of type Shape. This is the foundation of polymorphism!

8 A subclass CAN override a concrete (non-abstract) method and make it abstract

This is a powerful and often surprising rule. A subclass can take a method that was fully implemented in its parent, and re-declare it as abstract — forcing its own subclasses to provide a new implementation. This is the basis of the Manager Technique we will see next.

7 The Manager Technique — Forcing toString()

This is a real-world application of Rule 8 that every software manager should know.

💼 Real Scenario at a Software Company

👨‍💼 Software Manager:
Every class in our system must have a meaningful toString() method. This is our company standard — no exceptions!
👤 Junior Developer:
But manager, I always forget! When I create many classes, I sometimes miss it. Can you remind me?
👨‍💼 Manager (smiling):
I should not have to remind you every time. Let me make the compiler remind you instead!
💼 The Manager Technique — Making toString() Mandatory
// ── Step 1: Create a base class that forces toString() ────────── abstract class BaseEntity extends Object { // Take toString() from Object (which has a concrete version) // and re-declare it as ABSTRACT — this forces ALL subclasses to implement it! @Override public abstract String toString(); } // ── Step 2: All developers extend BaseEntity ───────────────────── class Student extends BaseEntity { private String name; private int id; public Student(String name, int id) { this.name = name; this.id = id; } // Compiler FORCES the developer to write this — they cannot skip it! @Override public String toString() { return "Student[id=" + id + ", name=" + name + "]"; } } class Course extends BaseEntity { private String code; private int credits; public Course(String code, int credits) { this.code = code; this.credits = credits; } @Override public String toString() { return "Course[" + code + ", credits=" + credits + "]"; } } // ── What happens if someone forgets? ───────────────────────────── class LazyDeveloper extends BaseEntity { private String data; // ❌ COMPILE ERROR: "LazyDeveloper is not abstract and does not // override abstract method toString() in BaseEntity" // The compiler forces them to implement it — manager is happy! }
🎉 Why This Is Powerful
  • The compiler becomes the manager's assistant — no reminders needed
  • A developer cannot compile their class without providing a proper toString()
  • This technique combines Rule 6 (abstract subclass of concrete superclass) and Rule 8 (making a concrete method abstract)
  • Used in real Java frameworks and large enterprise codebases

8 Case Study — java.lang.Number (Abstract in the Real Java API)

Everything we studied today exists right inside Java's standard library. The perfect example: java.lang.Number.

📌 What Is java.lang.Number?

Number is the abstract superclass of all numeric wrapper classes in Java. It is declared as:

public abstract class Number extends Object

It has abstract methods that every numeric subclass must implement. You cannot do new Number() — it is abstract!

🛠 abstract class Number
↓   extends   ↓
Integer
Double
Float
Long
Short
Byte
BigInteger
BigDecimal
📄 java.lang.Number — Simplified Declaration
// java.lang.Number — as declared in Java's source code (simplified) public abstract class Number extends Object { // Abstract methods — every subclass MUST implement these public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue(); } // Integer — one concrete subclass public final class Integer extends Number { private final int value; @Override public int intValue() { return value; } @Override public long longValue() { return (long) value; } @Override public float floatValue() { return (float) value; } @Override public double doubleValue() { return (double) value; } // ... many more methods }

Polymorphism Using Number as a Data Type

📄 Number as Polymorphic Type — Variable, Array, Method
// 1. Polymorphic VARIABLE ────────────────────────────────────────── Number n1 = new Integer(42); // Integer IS-A Number ✓ Number n2 = new Double(3.14); // Double IS-A Number ✓ Number n3 = new Float(2.5f); // Float IS-A Number ✓ Number n4 = new Long(100L); // Long IS-A Number ✓ // 2. Polymorphic ARRAY ───────────────────────────────────────────── Number[] numbers = { new Integer(10), new Double(3.14), new Float(2.5f), new Long(100L), new Short((short)5) }; for (Number num : numbers) { System.out.printf("int=%-6d double=%.2f%n", num.intValue(), num.doubleValue()); } // 3. Polymorphic METHOD ──────────────────────────────────────────── public static void showNumber(Number n) { // accepts ANY Number subclass System.out.println("Value as double: " + n.doubleValue()); } showNumber(new Integer(7)); showNumber(new BigInteger("999999999999999999"));
Output
int=10 double=10.00 int=3 double=3.14 int=2 double=2.50 int=100 double=100.00 int=5 double=5.00
💡 The Lesson from Number

Java's own designers used the abstract class pattern for Number for exactly the same reasons we use it for Shape: "Number" is too general to have its own object, but it provides a shared interface and IS-A relationship for all numeric types — enabling polymorphism across the entire numeric hierarchy.

Summary — What You Learned Today

Abstract ≠ Abstraction
Abstract class is a Java keyword. Abstraction is OOP's 2nd pillar. Different things!
🕐
Abstract Meaning
Abstract = vague, general, incomplete. Cannot represent a specific real-world object.
🖌
The Shape Story
"Draw a shape" — you cannot draw just a shape. It is too general. Same in Java: no new Shape().
🏪
Why Keep Shape?
Inheritance (avoid redundancy) + Polymorphism (IS-A relationship). Both require the superclass.
🛠
abstract keyword
Prevents instantiation. Class and/or method can be abstract. Compiler enforces rules.
📋
Abstract Method
Header only, no body. Forces subclasses to implement. 100% guarantees the behavior exists.
📙
8 Rules
All → concrete. Some → still abstract. Has abstract method → must be abstract. Can be data type. And more.
💼
Manager Technique
Make a concrete method abstract in a subclass to force all developers to implement it.
🔢
Number Case Study
java.lang.Number is abstract. Integer, Double, etc. extend it. Use Number as a polymorphic type.
📌 The Complete Definition

An abstract class is a class that is declared with the abstract keyword. It may contain abstract methods (header only, no body) and/or concrete methods. It cannot be instantiated, but it can be used as a data type for polymorphism. Any class that inherits abstract methods must either implement all of them (becoming concrete) or declare itself abstract too.

🎨 Code Block Theme