Abstraction in Java

Learn to hide complexity and show only what's necessary

💡 Think of abstraction like driving a car! You know how to drive (use the steering wheel, pedals, and gear shift) without knowing how the engine works inside. The car hides the complex engine details and only shows you the simple controls you need. That's abstraction - hiding complexity and showing only what matters!

🎨 What is Abstraction?

Abstraction means hiding the implementation details and showing only the functionality to the user. It focuses on WHAT an object does rather than HOW it does it. Think of it as a contract - 'I promise this method exists, but each class decides how to implement it.'

AbstractionBasics.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Abstract class - cannot create objects from it directly
abstract class Animal {
// Concrete method (has body) - all animals inherit this
public void sleep() {
System.out.println("Zzz... sleeping");
}
// Abstract method (no body) - each animal must implement its own
public abstract void makeSound();
// Another abstract method
public abstract void move();
}
// Concrete class - implements all abstract methods
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof! Woof!");
}
@Override
public void move() {
System.out.println("Dog is running");
}
}
class Bird extends Animal {
@Override
public void makeSound() {
System.out.println("Tweet! Tweet!");
}
@Override
public void move() {
System.out.println("Bird is flying");
}
}
class AbstractionDemo {
public static void main(String[] args) {
// Animal animal = new Animal(); // ❌ ERROR! Can't instantiate abstract class
// ✓ Create concrete classes
Animal myDog = new Dog();
Animal myBird = new Bird();
// Use them through abstract type
myDog.makeSound(); // "Woof! Woof!"
myDog.move(); // "Dog is running"
myDog.sleep(); // "Zzz... sleeping" (inherited)
myBird.makeSound(); // "Tweet! Tweet!"
myBird.move(); // "Bird is flying"
myBird.sleep(); // "Zzz... sleeping" (inherited)
}
}

Why Use Abstraction?

  • Hide Complexity: Users don't need to understand internal workings
  • Reduce Code Duplication: Common structure defined once
  • Increase Flexibility: Change implementation without affecting users
  • Enforce Structure: Force child classes to implement certain methods

📋 Abstract Classes

AbstractClass.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
abstract class Vehicle {
// Fields (can have state)
protected String brand;
protected int year;
protected boolean isRunning;
// Constructor (abstract classes can have constructors!)
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
this.isRunning = false;
}
// Abstract methods (no implementation)
public abstract void start();
public abstract void stop();
public abstract int getMaxSpeed();
// Concrete method (has implementation)
public void displayInfo() {
System.out.println("Brand: " + brand);
System.out.println("Year: " + year);
System.out.println("Max Speed: " + getMaxSpeed() + " km/h");
}
public boolean isRunning() {
return isRunning;
}
}
class Car extends Vehicle {
private int numberOfDoors;
public Car(String brand, int year, int doors) {
super(brand, year); // Call abstract class constructor
this.numberOfDoors = doors;
}
@Override
public void start() {
isRunning = true;
System.out.println(brand + " car engine starting... Vroom!");
}
@Override
public void stop() {
isRunning = false;
System.out.println(brand + " car engine stopped.");
}
@Override
public int getMaxSpeed() {
return 200; // Cars go up to 200 km/h
}
}
class Motorcycle extends Vehicle {
private boolean hasSidecar;
public Motorcycle(String brand, int year, boolean sidecar) {
super(brand, year);
this.hasSidecar = sidecar;
}
@Override
public void start() {
isRunning = true;
System.out.println(brand + " motorcycle starting... Brrrm!");
}
@Override
public void stop() {
isRunning = false;
System.out.println(brand + " motorcycle stopped.");
}
@Override
public int getMaxSpeed() {
return 180; // Motorcycles go up to 180 km/h
}
}
class VehicleDemo {
public static void main(String[] args) {
Vehicle car = new Car("Toyota", 2023, 4);
Vehicle bike = new Motorcycle("Harley", 2022, false);
car.start();
car.displayInfo();
System.out.println("Running: " + car.isRunning());
System.out.println();
bike.start();
bike.displayInfo();
System.out.println("Running: " + bike.isRunning());
}
}

🔌 Interfaces

Interfaces.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Interface - pure contract (100% abstraction)
interface Drawable {
void draw(); // public abstract by default
void resize(int scale);
}
interface Colorable {
void setColor(String color);
String getColor();
}
// A class can implement multiple interfaces!
class Circle implements Drawable, Colorable {
private int radius;
private String color;
private int x, y;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = "Black";
}
// Must implement all methods from both interfaces
@Override
public void draw() {
System.out.println("Drawing circle at (" + x + "," + y + ")");
System.out.println("Radius: " + radius + ", Color: " + color);
}
@Override
public void resize(int scale) {
radius *= scale;
System.out.println("Circle resized to radius: " + radius);
}
@Override
public void setColor(String color) {
this.color = color;
System.out.println("Circle color changed to: " + color);
}
@Override
public String getColor() {
return color;
}
}
class Rectangle implements Drawable, Colorable {
private int width, height;
private String color;
private int x, y;
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = "Black";
}
@Override
public void draw() {
System.out.println("Drawing rectangle at (" + x + "," + y + ")");
System.out.println("Size: " + width + "x" + height + ", Color: " + color);
}
@Override
public void resize(int scale) {
width *= scale;
height *= scale;
System.out.println("Rectangle resized to: " + width + "x" + height);
}
@Override
public void setColor(String color) {
this.color = color;
System.out.println("Rectangle color changed to: " + color);
}
@Override
public String getColor() {
return color;
}
}
class InterfaceDemo {
public static void main(String[] args) {
// Treat objects through interface types
Drawable shape1 = new Circle(100, 100, 50);
Drawable shape2 = new Rectangle(200, 150, 80, 60);
shape1.draw();
shape1.resize(2);
shape1.draw();
System.out.println();
shape2.draw();
shape2.resize(3);
shape2.draw();
// Can also use Colorable interface
Colorable colorShape = new Circle(50, 50, 25);
colorShape.setColor("Red");
System.out.println("Color: " + colorShape.getColor());
}
}

🛠️ Ways to Achieve Abstraction

1. Abstract Classes (0-100% abstraction)

Can have both abstract methods (without body) and concrete methods (with body)

abstract class Animal { abstract void sound(); void sleep() {...} }

2. Interfaces (100% abstraction)

All methods are abstract by default (until Java 8). Pure contract.

interface Drawable { void draw(); }

⚖️ Abstract Class vs Interface

AbstractVsInterface.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// ABSTRACT CLASS - Can have both abstract and concrete methods
abstract class Employee {
// Can have fields
protected String name;
protected double baseSalary;
// Can have constructor
public Employee(String name, double baseSalary) {
this.name = name;
this.baseSalary = baseSalary;
}
// Concrete method - shared by all employees
public void clockIn() {
System.out.println(name + " clocked in at work");
}
// Abstract method - each employee calculates differently
public abstract double calculateSalary();
public abstract void performDuties();
}
// INTERFACE - Pure contract
interface Promotable {
void promote(String newTitle);
boolean isEligibleForPromotion();
}
interface Trainable {
void attendTraining(String course);
int getTrainingHours();
}
// Class can extend ONE abstract class and implement MULTIPLE interfaces
class Developer extends Employee implements Promotable, Trainable {
private String title;
private int projectsCompleted;
private int trainingHours;
public Developer(String name, double baseSalary, String title) {
super(name, baseSalary);
this.title = title;
this.projectsCompleted = 0;
this.trainingHours = 0;
}
// Implement abstract methods from Employee
@Override
public double calculateSalary() {
return baseSalary + (projectsCompleted * 1000);
}
@Override
public void performDuties() {
System.out.println(name + " is writing code as " + title);
projectsCompleted++;
}
// Implement Promotable interface
@Override
public void promote(String newTitle) {
this.title = newTitle;
System.out.println(name + " promoted to: " + newTitle);
}
@Override
public boolean isEligibleForPromotion() {
return projectsCompleted >= 5 && trainingHours >= 40;
}
// Implement Trainable interface
@Override
public void attendTraining(String course) {
System.out.println(name + " attending: " + course);
trainingHours += 8;
}
@Override
public int getTrainingHours() {
return trainingHours;
}
}
class ComparisonDemo {
public static void main(String[] args) {
Developer dev = new Developer("Alice", 80000, "Junior Developer");
// Use inherited concrete method
dev.clockIn();
// Perform duties (abstract method implemented)
dev.performDuties();
dev.performDuties();
dev.performDuties();
// Attend training (interface method)
dev.attendTraining("Java Advanced");
dev.attendTraining("Spring Boot");
dev.attendTraining("Microservices");
dev.attendTraining("System Design");
dev.attendTraining("Leadership");
// Check promotion eligibility
if (dev.isEligibleForPromotion()) {
dev.promote("Senior Developer");
}
System.out.println("\nFinal Salary: $" + dev.calculateSalary());
System.out.println("Training Hours: " + dev.getTrainingHours());
}
}

🌟 Real-World Example: Database Connection

DatabaseAbstraction.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Abstract class defines common database operations
abstract class Database {
protected String host;
protected int port;
protected String username;
protected boolean connected;
public Database(String host, int port, String username) {
this.host = host;
this.port = port;
this.username = username;
this.connected = false;
}
// Abstract methods - each database implements differently
public abstract void connect();
public abstract void disconnect();
public abstract void executeQuery(String query);
// Concrete method - shared by all databases
public void showStatus() {
System.out.println("Host: " + host + ":" + port);
System.out.println("User: " + username);
System.out.println("Connected: " + connected);
}
}
class MySQLDatabase extends Database {
public MySQLDatabase(String host, int port, String username) {
super(host, port, username);
}
@Override
public void connect() {
System.out.println("Connecting to MySQL database...");
// MySQL-specific connection logic here
connected = true;
System.out.println("MySQL connected successfully!");
}
@Override
public void disconnect() {
System.out.println("Disconnecting from MySQL...");
connected = false;
System.out.println("MySQL disconnected.");
}
@Override
public void executeQuery(String query) {
if (!connected) {
System.out.println("Error: Not connected to MySQL");
return;
}
System.out.println("Executing MySQL query: " + query);
System.out.println("Query executed successfully!");
}
}
class PostgreSQLDatabase extends Database {
public PostgreSQLDatabase(String host, int port, String username) {
super(host, port, username);
}
@Override
public void connect() {
System.out.println("Establishing PostgreSQL connection...");
// PostgreSQL-specific connection logic here
connected = true;
System.out.println("PostgreSQL connected!");
}
@Override
public void disconnect() {
System.out.println("Closing PostgreSQL connection...");
connected = false;
System.out.println("PostgreSQL disconnected.");
}
@Override
public void executeQuery(String query) {
if (!connected) {
System.out.println("Error: Not connected to PostgreSQL");
return;
}
System.out.println("Running PostgreSQL query: " + query);
System.out.println("Query completed!");
}
}
class MongoDatabase extends Database {
public MongoDatabase(String host, int port, String username) {
super(host, port, username);
}
@Override
public void connect() {
System.out.println("Connecting to MongoDB...");
// MongoDB-specific connection logic here
connected = true;
System.out.println("MongoDB connected!");
}
@Override
public void disconnect() {
System.out.println("Closing MongoDB connection...");
connected = false;
System.out.println("MongoDB disconnected.");
}
@Override
public void executeQuery(String query) {
if (!connected) {
System.out.println("Error: Not connected to MongoDB");
return;
}
System.out.println("Executing MongoDB query: " + query);
System.out.println("Query executed!");
}
}
class DatabaseDemo {
// This method works with ANY database type!
public static void performDatabaseOperations(Database db) {
db.showStatus();
db.connect();
db.executeQuery("SELECT * FROM users");
db.disconnect();
System.out.println();
}
public static void main(String[] args) {
Database mysql = new MySQLDatabase("localhost", 3306, "admin");
Database postgres = new PostgreSQLDatabase("192.168.1.100", 5432, "dev");
Database mongo = new MongoDatabase("cloud.server.com", 27017, "user");
// Same method works with all database types!
performDatabaseOperations(mysql);
performDatabaseOperations(postgres);
performDatabaseOperations(mongo);
// Abstraction hides the complexity!
}
}

🔗 Multiple Interface Implementation

MultipleInterfaces.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
interface Flyable {
void fly();
int getMaxAltitude();
}
interface Swimmable {
void swim();
int getMaxDepth();
}
interface Walkable {
void walk();
int getMaxSpeed();
}
// Duck can do all three!
class Duck implements Flyable, Swimmable, Walkable {
private String name;
public Duck(String name) {
this.name = name;
}
@Override
public void fly() {
System.out.println(name + " is flying through the air!");
}
@Override
public int getMaxAltitude() {
return 500; // meters
}
@Override
public void swim() {
System.out.println(name + " is swimming in the water!");
}
@Override
public int getMaxDepth() {
return 3; // meters
}
@Override
public void walk() {
System.out.println(name + " is waddling on land!");
}
@Override
public int getMaxSpeed() {
return 5; // km/h
}
}
// Fish can only swim
class Fish implements Swimmable {
private String species;
public Fish(String species) {
this.species = species;
}
@Override
public void swim() {
System.out.println(species + " is swimming gracefully!");
}
@Override
public int getMaxDepth() {
return 100; // meters
}
}
// Bird can fly and walk
class Sparrow implements Flyable, Walkable {
private String name;
public Sparrow(String name) {
this.name = name;
}
@Override
public void fly() {
System.out.println(name + " is soaring in the sky!");
}
@Override
public int getMaxAltitude() {
return 1000; // meters
}
@Override
public void walk() {
System.out.println(name + " is hopping on the ground!");
}
@Override
public int getMaxSpeed() {
return 3; // km/h
}
}
class MultiInterfaceDemo {
public static void main(String[] args) {
Duck duck = new Duck("Donald");
Fish fish = new Fish("Nemo");
Sparrow sparrow = new Sparrow("Jack");
System.out.println("=== Duck (can do everything!) ===");
duck.fly();
duck.swim();
duck.walk();
System.out.println("\n=== Fish (only swims) ===");
fish.swim();
System.out.println("Max depth: " + fish.getMaxDepth() + "m");
System.out.println("\n=== Sparrow (flies and walks) ===");
sparrow.fly();
sparrow.walk();
System.out.println("Max altitude: " + sparrow.getMaxAltitude() + "m");
}
}

🔑 Key Concepts

Abstract Class

Cannot be instantiated, can have abstract and concrete methods

abstract class Shape { abstract double area(); }

Abstract Method

Method without body, must be implemented by child class

abstract void methodName();

Interface

Contract that classes must follow, all methods abstract (pre-Java 8)

interface Printable { void print(); }

implements Keyword

Used to implement an interface

class Document implements Printable { }

Best Practices

  • Use abstract classes when classes share common code
  • Use interfaces when defining pure contracts/capabilities
  • Name interfaces with adjectives (Runnable, Drawable, Printable)
  • Keep interfaces focused - don't make them too large
  • Abstract classes can have constructors, interfaces cannot
  • A class can implement multiple interfaces but extend only one abstract class

💼 Interview Tips

  • Abstract class vs Interface: Abstract can have state and concrete methods
  • You cannot create instance of abstract class (new AbstractClass() ❌)
  • Abstract method has no body, ends with semicolon
  • Child must implement all abstract methods or be abstract itself
  • Interfaces support multiple inheritance, abstract classes don't
  • From Java 8: interfaces can have default and static methods