Skip to content

Java Abstraction

Abstraction is one of the core concepts of Object-Oriented Programming (OOP). It focuses on hiding complex implementation details and exposing only the essential features or functionalities of an object or system.

Think about driving a car: you interact with essential controls like the steering wheel, accelerator, and brakes (abstraction), without needing to know the intricate details of the engine’s internal combustion or the braking system’s hydraulics (implementation details).

In Java, abstraction is primarily achieved using:

  • Abstract Classes: Classes that cannot be instantiated and may contain abstract methods.
  • Interfaces: Reference types that define a contract of abstract methods (and potentially default/static methods).

This chapter focuses on Abstract Classes.

An abstract class serves as a template or blueprint for other classes. It is declared using the abstract keyword.

  • Cannot be Instantiated: You cannot create an object directly from an abstract class using the new keyword.
  • Can Have Abstract Methods: Methods declared with the abstract keyword and without an implementation (no method body, ends with a semicolon). If a class contains even one abstract method, the class itself must be declared abstract.
  • Can Have Concrete Methods: Can contain regular methods with implementations.
  • Can Have Constructors: Abstract classes can have constructors, which are called when an instance of a concrete subclass is created (typically via super() call from the subclass constructor).
  • Can Have Fields: Can have instance variables (state) and static variables.
  • Subclassing: Designed to be subclassed (extended). Concrete (non-abstract) subclasses must provide implementations for all inherited abstract methods.
  • Code Reusability: Provide common fields and method implementations that subclasses can inherit.
  • Enforce Structure: Define a common structure and required methods (abstract methods) that all subclasses must implement, ensuring consistency.
  • Template Design: Act as a base for related classes, defining a general concept or entity that is too abstract to exist on its own but provides a foundation for specific types.
  • Polymorphism: Allow treating objects of different subclasses through a reference of the abstract class type.

Use the abstract keyword before the class keyword.

/* FileName: Shape.java */
public abstract class Shape {
private String color;
// Constructor (called by subclasses)
public Shape(String color) {
System.out.println("Shape constructor called for color: " + color);
this.color = color;
}
// Concrete method (shared implementation)
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
// Abstract method (must be implemented by concrete subclasses)
public abstract double calculateArea();
// Another abstract method
public abstract void draw();
}

Trying to instantiate an abstract class results in a compile-time error:

// This will cause a compilation error:
// Shape myShape = new Shape("Red"); // Error: Shape is abstract; cannot be instantiated

A concrete class extends an abstract class using the extends keyword. It must provide implementations for all abstract methods inherited from the abstract parent class. Use the @Override annotation for clarity and compiler checks.

/* FileName: Circle.java */
public class Circle extends Shape { // Extends the abstract Shape class
private double radius;
public Circle(String color, double radius) {
super(color); // Call the constructor of the abstract parent class
System.out.println("Circle constructor called.");
this.radius = radius;
}
public double getRadius() {
return radius;
}
// Implementation of the abstract method from Shape
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
// Implementation of the other abstract method from Shape
@Override
public void draw() {
System.out.println("Drawing a " + getColor() + " circle with radius " + radius);
}
}
/* FileName: Rectangle.java */
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(String color, double width, double height) {
super(color);
System.out.println("Rectangle constructor called.");
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
return width * height;
}
@Override
public void draw() {
System.out.println("Drawing a " + getColor() + " rectangle with width " + width + " and height " + height);
}
}

Using Abstract Classes and Subclasses (Polymorphism)

Section titled “Using Abstract Classes and Subclasses (Polymorphism)”

You can create objects of the concrete subclasses and use polymorphism to refer to them using the abstract class type.

/* FileName: AbstractionDemo.java */
public class AbstractionDemo {
public static void main(String[] args) {
// Cannot create Shape object: Shape s1 = new Shape("Blue"); // Error!
// Create objects of concrete subclasses
Shape circle = new Circle("Red", 5.0);
Shape rectangle = new Rectangle("Blue", 4.0, 6.0);
System.out.println("\n--- Circle Info ---");
System.out.println("Color: " + circle.getColor()); // Inherited concrete method
System.out.println("Area: " + circle.calculateArea()); // Overridden abstract method
circle.draw(); // Overridden abstract method
// circle.getRadius(); // Error: getRadius() is not in Shape. Need casting:
if (circle instanceof Circle) {
Circle c = (Circle) circle;
System.out.println("Radius: " + c.getRadius());
}
System.out.println("\n--- Rectangle Info ---");
System.out.println("Color: " + rectangle.getColor());
System.out.println("Area: " + rectangle.calculateArea());
rectangle.draw();
System.out.println("\n--- Polymorphism with Array ---");
Shape[] shapes = { circle, rectangle, new Circle("Green", 2.5) };
for (Shape currentShape : shapes) {
currentShape.draw(); // Calls the specific draw() method of Circle or Rectangle
System.out.println("Area: " + currentShape.calculateArea());
System.out.println("--");
}
}
}

Expected Output (Illustrative):

Shape constructor called for color: Red
Circle constructor called.
Shape constructor called for color: Blue
Rectangle constructor called.
--- Circle Info ---
Color: Red
Area: 78.53981633974483
Drawing a Red circle with radius 5.0
Radius: 5.0
--- Rectangle Info ---
Color: Blue
Area: 24.0
Drawing a Blue rectangle with width 4.0 and height 6.0
--- Polymorphism with Array ---
Shape constructor called for color: Green
Circle constructor called.
Drawing a Red circle with radius 5.0
Area: 78.53981633974483
--
Drawing a Blue rectangle with width 4.0 and height 6.0
Area: 24.0
--
Drawing a Green circle with radius 2.5
Area: 19.634954084936208
--

Both abstract classes and interfaces are used for abstraction, but have key differences:

  • Inheritance: A class can extend only ONE abstract class, but implement MULTIPLE interfaces.
  • Fields: Abstract classes can have instance variables (state). Interfaces primarily have public static final constants (though technically possible to simulate state poorly with default methods, it’s not their intended use).
  • Methods: Abstract classes can have both abstract and concrete methods. Interfaces have abstract methods, and since Java 8, can also have default (implemented) and static methods.
  • Constructors: Abstract classes can have constructors; interfaces cannot.
  • Purpose: Use an abstract class for an “is-a” relationship where subclasses share common state and implementation. Use an interface for a “has-a” or “can-do” relationship, defining a capability or contract that potentially unrelated classes can fulfill.