Abstraction and Interfaces in Java: Abstract Classes, Contracts and Runnable Examples
Learn when Java needs an abstract class, when it needs an interface, and how both work together in one runnable charge-calculation program with exact outputs.
KnowledgeGate Team
Exam prep & CS education

Java provides both abstract classes and interfaces because shared state and cross-type contracts are different design needs. Both can hide implementation details and support polymorphism. BikeDelivery and VanDelivery reuse state and calculation code through an abstract base, while Packaging joins them only through the Chargeable interface.
Abstraction in Java: expose the operation, hide the mechanism
Abstraction presents the operations a caller needs while keeping implementation choices behind them. With item.calculateCharge(), the caller asks for a charge without knowing whether the object uses distance, vehicle type or item count.
An abstract class can hold object state, run a constructor, reuse concrete methods and leave selected methods abstract. An interface defines a contract that unrelated classes can implement. Avoid the inaccurate shortcut that calls these partial and complete abstraction. OOP for Teaching CS Exams: Classes and Inheritance places abstraction beside the other OOP ideas; Coding & DSA Courses for Placements is the broader learning path.
Term | Meaning in this model |
|---|---|
Abstraction | Expose an operation while hiding its formula |
Abstract class | Non-instantiable base with state and shared code |
Abstract method | Method implemented by a subclass |
Interface | Operations an implementing type promises |
| Builds class inheritance |
| Adopts an interface |
Contract | Behaviour callers may depend on |
Abstract classes in Java: build the shared Delivery base
abstract class Delivery owns private final fields trackingId and distanceKm. Its constructor rejects a negative distance with IllegalArgumentException("Distance cannot be negative"). The protected final method distanceKm() exposes the validated value to subclasses without exposing the field.
baseCharge() returns 40, while protected abstract int ratePerKm(); leaves one choice open. The shared calculation is baseCharge() + distanceKm() * ratePerKm(). BikeDelivery returns 8; VanDelivery returns 14.
The constructor initialises shared state for subclass objects, although new Delivery(...) is forbidden. Both subclasses call super(...) and reuse validation and calculation, but cannot read the private fields directly.
Interfaces in Java: define one contract for unrelated charge types
Chargeable declares String label(); and int calculateCharge();. They are public contract methods, so implementations must be public. Interfaces may also have default and static methods, but the contract is the important idea here.
Delivery implements Chargeable with final public implementations; its subclasses only choose ratePerKm(). Unrelated Packaging also implements the interface, stores items and chargePerItem, and returns items * chargePerItem.
Bike and van share state and an algorithm. Packaging shares neither, yet all three fit a Chargeable[] because they promise the loop's two operations.

Abstraction and interfaces worked example: run one calculation loop
Save the following source as AbstractionDemo.java:
interface Chargeable {
String label();
int calculateCharge();
}
abstract class Delivery implements Chargeable {
private final String trackingId;
private final int distanceKm;
Delivery(String trackingId, int distanceKm) {
if (distanceKm < 0) {
throw new IllegalArgumentException("Distance cannot be negative");
}
this.trackingId = trackingId;
this.distanceKm = distanceKm;
}
protected final int distanceKm() {
return distanceKm;
}
protected int baseCharge() {
return 40;
}
protected abstract int ratePerKm();
@Override
public final String label() {
return trackingId;
}
@Override
public final int calculateCharge() {
return baseCharge() + distanceKm() * ratePerKm();
}
}
class BikeDelivery extends Delivery {
BikeDelivery(String trackingId, int distanceKm) {
super(trackingId, distanceKm);
}
@Override
protected int ratePerKm() {
return 8;
}
}
class VanDelivery extends Delivery {
VanDelivery(String trackingId, int distanceKm) {
super(trackingId, distanceKm);
}
@Override
protected int ratePerKm() {
return 14;
}
}
class Packaging implements Chargeable {
private final int items;
private final int chargePerItem;
Packaging(int items, int chargePerItem) {
if (items <= 0 || chargePerItem < 0) {
throw new IllegalArgumentException("Invalid packaging values");
}
this.items = items;
this.chargePerItem = chargePerItem;
}
@Override
public String label() {
return "Packaging";
}
@Override
public int calculateCharge() {
return items * chargePerItem;
}
}
public class AbstractionDemo {
public static void main(String[] args) {
Chargeable[] items = {
new BikeDelivery("KG-101", 12),
new VanDelivery("KG-102", 12),
new Packaging(3, 25)
};
int total = 0;
for (Chargeable item : items) {
int charge = item.calculateCharge();
System.out.println(item.label() + ": " + charge);
total += charge;
}
System.out.println("Total: " + total);
}
}Compile and run it:
javac AbstractionDemo.java
java AbstractionDemoTrace the values before checking the output:
Bike:
40 + 12 * 8 = 136.Van:
40 + 12 * 14 = 208.Packaging:
3 * 25 = 75.Total:
136 + 208 + 75 = 419.
KG-101: 136
KG-102: 208
Packaging: 75
Total: 419The Chargeable loop can call only label() and calculateCharge(). It needs no distance, rate or packaging fields because runtime dispatch selects the implementation. The Java Course: Concepts, MCQs & Coding Questions teaches the surrounding sequence.

Abstract class vs interface: choose from the relationship
Choose Delivery because bike and van share validated state and a calculation template. Choose Chargeable because deliveries and packaging need one contract despite different data.
Decision point | Abstract class | Interface |
|---|---|---|
Purpose | Related class family | Cross-type contract |
Per-object state | Instance fields allowed | No ordinary instance fields |
Constructors | Yes | No |
Reusable implementation | Concrete methods | Optional default and static methods |
Syntax used by a class |
|
|
Number adopted by one class | One superclass | Multiple interfaces |
Interface constants are shared, not replacements for object state. Packaging extends Delivery would invent a false is-a relationship. Making Chargeable an abstract class would block a class that already has a superclass. The two tools often cooperate instead of competing.
Common abstraction and interface errors in Java
Mistake | What goes wrong | Fix |
|---|---|---|
| Abstract class cannot be instantiated | Construct a concrete delivery |
Concrete class omits | Abstract method remains incomplete | Implement it or make the class abstract |
| Class cannot extend an interface | Use |
Package-private | Weaker than public contract access | Use |
| Abstract method has a body | Use |
State in interface fields | Fields become shared constants | Keep state private in classes |
Do not recover concrete types with casts or instanceof. A genuinely needed loop operation belongs in Chargeable.
How assessments test abstraction and interfaces
With Chargeable c = new BikeDelivery("KG-201", 5);, c.calculateCharge() prints 80: the inherited algorithm uses the bike rate, so 40 + 5 * 8 = 80. c.ratePerKm() is unavailable because the protected method is outside the interface contract.
Use these checkable exercises:
Add
DroneDeliverywith rate10.new DroneDelivery("KG-103", 7)gives40 + 7 * 10 = 110; the array total becomes419 + 110 = 529.Add
GiftWrap implements Chargeablefor2parcels at35each. It printsGiftWrap: 70; the total becomes419 + 70 = 489.Run
new Packaging(0, 25). It must be rejected with the exact messageInvalid packaging values.
Be ready to define the contract, locate state, trace dispatch and justify each type. Technical Interview: OS, DBMS, CN & OOP Prep is the broader revision route.
Abstraction and interfaces in Java: the short version
Abstraction exposes needed operations and hides their mechanisms.
Abstract classes combine object state with incomplete behaviour.
Interfaces define contracts across implementations.
extendsbuilds a class hierarchy.implementsadopts a contract.
The total 419 proves that one interface loop combines different mechanisms. Retype the program and change both distances to 9. Predict bike 40 + 9 * 8 = 112, van 40 + 9 * 14 = 166, packaging 75, and total 112 + 166 + 75 = 353, then run it. Add DroneDelivery("KG-103", 7) to the original array and verify 529.
To apply interfaces to collections and data structures, continue with DSA Using Java: Placement Preparation Course. If your fundamentals are uncertain, use the Java course linked after the trace first. Finish by coding both changes without copying the outputs.
Keep learning

Wrapper Classes and Autoboxing in Java: Worked Examples and Null Traps
Learn why Java wrapper classes exist, how boxing and unboxing work, and where nulls, reference identity, and overload selection create surprises.

Synchronization in Java: Monitors, Race Conditions and Runnable Examples
Learn why Java threads lose updates, what each synchronized form locks, and how to build safe counters, inventory checks and condition-waiting code.

Java Streams API Tutorial: Filter, Map, Reduce and Collect with Runnable Examples
Learn Java streams from the source-to-terminal mental model, then trace operations, reductions and collectors through runnable examples and practice tasks.

Optional in Java: Null-Safe Patterns with Runnable Examples
Learn Java Optional from creation to stream pipelines through one user lookup. Trace present and empty paths, compare fallbacks, and repair common mistakes.