Introduction
Abstract classes and interfaces both provide abstraction but have different features and use cases.
Quick Comparison
| Feature | Abstract Class | Interface |
|---|---|---|
| Keyword | abstract class | interface |
| Methods | Abstract + Concrete | Abstract (+ default in Java 8+) |
| Variables | Any type | public static final only |
| Constructor | Yes | No |
| Inheritance | Single (extends) | Multiple (implements) |
| Access modifiers | All | public only |
| Fields | Instance variables | Constants only |
| When to use | IS-A + shared code | CAN-DO capability |
Abstract Class Example
abstract class Animal {
String name; // Instance variable
// Constructor
Animal(String name) {
this.name = name;
}
// Concrete method
void sleep() {
System.out.println(name + " is sleeping");
}
// Abstract method
abstract void sound();
}
class Dog extends Animal {
Dog(String name) {
super(name);
}
@Override
void sound() {
System.out.println(name + " barks");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog("Buddy");
dog.sound(); // Buddy barks
dog.sleep(); // Buddy is sleeping
}
}
Interface Example
interface Animal {
// Constant
int LEGS = 4;
// Abstract methods
void sound();
void eat();
}
class Dog implements Animal {
String name;
Dog(String name) {
this.name = name;
}
@Override
public void sound() {
System.out.println(name + " barks");
}
@Override
public void eat() {
System.out.println(name + " eats food");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog("Buddy");
dog.sound(); // Buddy barks
dog.eat(); // Buddy eats food
System.out.println("Legs: " + Animal.LEGS);
}
}
Methods
Abstract Class:
abstract class Example {
// Abstract method
abstract void method1();
// Concrete method
void method2() {
System.out.println("Implemented method");
}
// Static method
static void method3() {
System.out.println("Static method");
}
// Final method
final void method4() {
System.out.println("Cannot override");
}
}
Interface:
interface Example {
// Abstract method (implicit)
void method1();
// Default method (Java 8+)
default void method2() {
System.out.println("Default method");
}
// Static method (Java 8+)
static void method3() {
System.out.println("Static method");
}
}
Variables
Abstract Class:
abstract class Example {
// Instance variable
int x = 10;
// Static variable
static int y = 20;
// Final variable
final int z = 30;
// Can be private, protected, public
private int a = 1;
protected int b = 2;
public int c = 3;
}
Interface:
interface Example {
// All variables are public static final
int X = 10; // public static final (implicit)
// Cannot have:
// private int a = 1; // ✗ Error
// protected int b = 2; // ✗ Error
// int c; // ✗ Must initialize
}
Constructor
Abstract Class:
abstract class Animal {
String name;
// Has constructor
Animal(String name) {
this.name = name;
System.out.println("Animal constructor");
}
}
class Dog extends Animal {
Dog(String name) {
super(name); // Call parent constructor
}
}
Interface:
interface Animal {
// No constructor allowed
// Animal() { } // ✗ Error
}
class Dog implements Animal {
// Own constructor
Dog() {
System.out.println("Dog constructor");
}
}
Inheritance
Abstract Class (Single):
abstract class Animal { }
abstract class Mammal { }
// ✗ Cannot extend multiple classes
// class Dog extends Animal, Mammal { }
// ✓ Only one
class Dog extends Animal { }
Interface (Multiple):
interface Walkable { }
interface Swimmable { }
interface Flyable { }
// ✓ Can implement multiple interfaces
class Duck implements Walkable, Swimmable, Flyable { }
Complete Comparison Example
// Abstract Class
abstract class Vehicle {
String brand; // Instance variable
Vehicle(String brand) { // Constructor
this.brand = brand;
}
void displayBrand() { // Concrete method
System.out.println("Brand: " + brand);
}
abstract void start(); // Abstract method
}
// Interface
interface Drivable {
int MAX_SPEED = 200; // Constant
void drive(); // Abstract method
void stop(); // Abstract method
}
// Class using both
class Car extends Vehicle implements Drivable {
Car(String brand) {
super(brand);
}
@Override
void start() {
System.out.println(brand + " car starting");
}
@Override
public void drive() {
System.out.println(brand + " car driving");
}
@Override
public void stop() {
System.out.println(brand + " car stopping");
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car("Toyota");
car.displayBrand(); // From abstract class
car.start(); // Implemented abstract method
car.drive(); // From interface
car.stop(); // From interface
System.out.println("Max speed: " + Drivable.MAX_SPEED);
}
}
When to Use Abstract Class?
Use when:
- Shared code among related classes
- Common state (instance variables)
- Constructor needed
- IS-A relationship (Dog IS-A Animal)
- Single inheritance is enough
abstract class Employee {
protected String name;
protected double salary;
Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
void displayInfo() {
System.out.println(name + ": $" + salary);
}
abstract double calculateBonus();
}
class Manager extends Employee {
Manager(String name, double salary) {
super(name, salary);
}
@Override
double calculateBonus() {
return salary * 0.2;
}
}
When to Use Interface?
Use when:
- Multiple inheritance needed
- Unrelated classes share behavior
- Contract/Capability (CAN-DO)
- No shared state needed
- Loose coupling desired
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
// Bird can fly
class Bird implements Flyable {
public void fly() {
System.out.println("Bird flying");
}
}
// Duck can both fly and swim
class Duck implements Flyable, Swimmable {
public void fly() {
System.out.println("Duck flying");
}
public void swim() {
System.out.println("Duck swimming");
}
}
// Fish can only swim
class Fish implements Swimmable {
public void swim() {
System.out.println("Fish swimming");
}
}
Using Both Together
abstract class Animal {
protected String name;
Animal(String name) {
this.name = name;
}
void sleep() {
System.out.println(name + " is sleeping");
}
abstract void eat();
}
interface Pet {
void play();
}
interface Guard {
void protect();
}
class Dog extends Animal implements Pet, Guard {
Dog(String name) {
super(name);
}
@Override
void eat() {
System.out.println(name + " is eating");
}
@Override
public void play() {
System.out.println(name + " is playing");
}
@Override
public void protect() {
System.out.println(name + " is protecting");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Max");
dog.eat(); // From Animal
dog.sleep(); // From Animal
dog.play(); // From Pet interface
dog.protect(); // From Guard interface
}
}
Real-World Example
// Abstract class for shared employee data and behavior
abstract class Employee {
protected String id;
protected String name;
protected double salary;
Employee(String id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
void displayBasicInfo() {
System.out.println("ID: " + id);
System.out.println("Name: " + name);
System.out.println("Salary: $" + salary);
}
abstract double calculateBonus();
}
// Interfaces for capabilities
interface Manageable {
void manage();
}
interface Teachable {
void teach();
}
interface Programmable {
void program();
}
// Manager can manage
class Manager extends Employee implements Manageable {
Manager(String id, String name, double salary) {
super(id, name, salary);
}
@Override
double calculateBonus() {
return salary * 0.3;
}
@Override
public void manage() {
System.out.println(name + " is managing team");
}
}
// Developer can program and teach
class Developer extends Employee implements Programmable, Teachable {
Developer(String id, String name, double salary) {
super(id, name, salary);
}
@Override
double calculateBonus() {
return salary * 0.2;
}
@Override
public void program() {
System.out.println(name + " is programming");
}
@Override
public void teach() {
System.out.println(name + " is teaching");
}
}
public class Main {
public static void main(String[] args) {
Manager mgr = new Manager("M001", "Alice", 50000);
mgr.displayBasicInfo();
mgr.manage();
System.out.println("Bonus: $" + mgr.calculateBonus());
System.out.println();
Developer dev = new Developer("D001", "Bob", 40000);
dev.displayBasicInfo();
dev.program();
dev.teach();
System.out.println("Bonus: $" + dev.calculateBonus());
}
}
Migration Strategy
Abstract Class to Interface:
- Remove instance variables
- Remove constructors
- Make all methods public
- Remove concrete methods (or make default)
Interface to Abstract Class:
- Add instance variables if needed
- Add constructor
- Add concrete methods
- Keep abstract methods
Quick Reference
// Abstract Class
abstract class AbstractExample {
int x; // Instance variable
AbstractExample() { } // Constructor
void concreteMethod() { } // Concrete method
abstract void abstractMethod(); // Abstract method
}
class Child extends AbstractExample {
void abstractMethod() { }
}
// Interface
interface InterfaceExample {
int X = 10; // Constant
void method(); // Abstract method
}
class Implementer implements InterfaceExample {
public void method() { }
}
// Both
class Combined extends AbstractExample implements InterfaceExample {
void abstractMethod() { }
public void method() { }
}
Exam Tips
Remember:
- Abstract class: partial implementation
- Interface: contract/capability
- Abstract class has constructor
- Interface has only constants
- Single inheritance for abstract class
- Multiple inheritance for interface
- extends for abstract class
- implements for interface
- Use both when needed
- Choose based on IS-A vs CAN-DO
Common Questions:
- Abstract class vs interface?
- When to use abstract class?
- When to use interface?
- Can class extend both?
- Difference in variables?
- Constructor difference?
- Multiple inheritance?
- Which is more flexible?
- Real-world usage scenarios?
- Can interface extend abstract class?