Java Notes
Understand abstraction in Java — hiding internal complexity, showing only what is needed, and achieving abstraction through abstract classes and interfaces.
Abstraction means showing only what is necessary and hiding everything else. Users of your code see a clean, simple interface. They do not need to know how it works internally.
You use abstraction every day: when you press a TV remote button, you do not think about the infrared signal, the receiver circuit, or the firmware. You just press a button and the channel changes. That is abstraction — a simple operation hiding complex implementation.
Abstraction vs Encapsulation
These two are related but different:
| Encapsulation | Abstraction | |
|---|---|---|
| What it does | Hides data (using private fields) | Hides implementation (using abstract methods/interfaces) |
| Focus | Protecting internal state | Simplifying what the user sees |
| Achieved with | Access modifiers | Abstract classes and interfaces |
Encapsulation: the TV remote hides the battery (private data). Abstraction: the TV remote shows only buttons (simple interface hiding complex circuitry).
How Java Achieves Abstraction
Java provides two tools:
- Abstract classes — partial abstraction. Can have both abstract methods (no body) and concrete methods (with body).
- Interfaces — full abstraction. Define only method signatures; each implementing class provides the body.
Abstract Method — A Method With No Body
An abstract method declares what a class can do, without saying how. Every non-abstract child must provide the how.
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Line by line:
abstract class Animal— the class is abstract. You cannot createnew Animal()directly.abstract void makeSound();— declared without a body. Every non-abstract child must provide one.void breathe()— has a body. All animals inherit this.Dogprovides its ownmakeSound().Catprovides its own.Animal a1 = new Dog("Bruno");— upcasting. The reference isAnimal, the object isDog.a1.makeSound()— runtime polymorphism picks Dog's version.
Interface — Full Abstraction
An interface is a contract. It says "any class that implements me must provide these methods." It provides no implementation at all (by default).
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Line by line:
interface Printable— declares two methods. No bodies.implements Printable— the class promises to provide both methods.Printable p1 = new Invoice(...)— the reference is the interface. Code only seesprint()andprintToPDF().- Any class that implements
Printableworks the same way here — full abstraction.
The Real Purpose of Abstraction
Abstraction separates what a method does from how it does it. The caller only knows the "what." The "how" can change without breaking the caller.
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
OrderService never knows whether it is talking to Razorpay or Stripe. It only knows the PaymentGateway interface. Switch the implementation by changing one line — no other code changes.
Common Mistake 1: Trying to Create an Object of an Abstract Class
Animal a = new Animal(); // COMPILE ERROR — Animal is abstract
Animal a = new Dog("Bruno"); // CORRECT — create through concrete subclassCommon Mistake 2: Not Implementing All Interface Methods
public class BadPrinter implements Printable {
@Override
public void print() { System.out.println("Printing"); }
// printToPDF() is missing — COMPILE ERROR
}If a class says implements Printable, it must provide every method the interface declares.
Practice Task
Task: Create an interface Shape with one method area() returning double. Create two classes Circle (field: radius) and Square (field: side) that both implement Shape. In main, create one of each, store them in a Shape[], and print each area.
Hint: Circle.area() returns 3.14159 * radius * radius. Square.area() returns side * side. The array type is Shape — the interface.
Solution:
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
What to observe: s.area() knows nothing about the actual type — it just calls through the interface. Add a Triangle class implementing Shape and the loop handles it instantly with no changes.
Continue the lesson path