Java Class vs Interface - Complete Comparison
Master the differences between Java Classes and Interfaces: Learn when to use each, practical examples, abstract classes, multiple inheritance, and best practices.
1. Classes vs Interfaces
Classes define complete objects with state and behavior. Interfaces define contracts that classes implement, specifying what methods must exist without mandating how.
- Class: fields + methods + constructors
- Interface: abstract method contracts
- Class supports single inheritance
- Interface supports multiple implementation
interface Drawable { void draw(); }
class Circle implements Drawable {
public void draw() { System.out.println("Drawing circle"); }
}
2. Abstract Class and Abstract Method
What is an abstract class?
An abstract class is declared with the abstract keyword. It cannot be instantiated with new — it exists to be extended by subclasses. It can contain:
- Abstract methods — no body; child must implement
- Concrete methods — shared code for all children
- Fields and constructors — shared state
What is an abstract method?
An abstract method has only a signature, no method body. It ends with ; and forces every non-abstract subclass to provide an implementation (unless the subclass is also abstract).
abstract class Shape {
String color;
Shape(String color) {
this.color = color;
}
// Abstract method — no body, subclass must implement
abstract double area();
// Concrete method — shared by all shapes
void displayColor() {
System.out.println("Color: " + color);
}
}
class Circle extends Shape {
double radius;
Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
double area() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
double width, height;
Rectangle(String color, double w, double h) {
super(color);
width = w;
height = h;
}
@Override
double area() {
return width * height;
}
}
public class AbstractDemo {
public static void main(String[] args) {
// Shape s = new Shape("red"); // ERROR — cannot instantiate abstract class
Shape c = new Circle("red", 5);
Shape r = new Rectangle("blue", 4, 6);
System.out.println("Circle area: " + c.area());
System.out.println("Rectangle area: " + r.area());
}
}
Remember
If a class has any abstract method, the class must be declared abstract. Abstract class = partial blueprint; concrete subclass = complete implementation.
3. Class vs Interface vs Abstract Class — Comparison Table
| Feature | Class | Abstract class | Interface |
|---|---|---|---|
| Keyword | class |
abstract class |
interface |
| Instantiation | Yes (new) |
No | No |
| Inheritance / implements | extends one class |
extends one class |
implements many interfaces |
| Methods with body | Yes | Yes (mixed with abstract) | Yes (default, static since Java 8) |
| Abstract methods | No | Yes | Yes (implicitly public abstract) |
| Constructors | Yes | Yes | No |
| Instance fields | Yes | Yes | Only public static final constants (traditionally) |
| Access modifiers on methods | Any | Any | public (implicit) |
| Multiple inheritance | No (one class) | No (one class) | Yes (many interfaces) |
| Best for | Complete objects with state | IS-A + shared code + forced overrides | CAN-DO contracts, loose coupling |
4. When to Use Class vs Interface?
| Use a class (concrete) when… | Use an interface when… |
|---|---|
| You need a full object with state and behavior | You need a contract (what methods exist) |
| Related types share a true IS-A relationship | Unrelated classes share a CAN-DO capability |
| You want constructors and instance fields | You want multiple types to implement the same role |
| Implementation is fixed in one place | Implementation varies per class; caller should not care |
Use an abstract class when subclasses are IS-A related and you want to share fields + some common method code, while forcing specific methods to be overridden.
Real-life examples
| Scenario | Choose | Reason |
|---|---|---|
Student, Employee as full records with name, id |
Class | Concrete entities with data and methods |
Payment — Card, UPI, Cash all must pay() |
Interface | Same contract, different unrelated payment classes |
DatabaseConnection — MySQL, PostgreSQL, MongoDB |
Interface | Swap implementation without changing app code |
Animal with shared eat(), each species has unique sound() |
Abstract class | Shared code + abstract method per species |
Comparable, Serializable on many unrelated classes |
Interface | Capability mixed into any class hierarchy |
List in Java Collections API |
Interface | ArrayList, LinkedList — program to List |
Bank Account base with SavingsAccount, CurrentAccount |
Class or abstract class | Shared balance logic; specialized interest rules |
Smartphone implements Camera, GPS, MusicPlayer |
Interface | Multiple independent capabilities on one device |
Servlet API — HttpServlet with template doGet/doPost |
Abstract class | Framework provides common code; you override hooks |
Logging — Logger with console, file, cloud implementations |
Interface | Inject any logger; easy testing with mock |
// Interface — CAN pay (contract)
interface Payment {
boolean pay(double amount);
}
class CardPayment implements Payment {
public boolean pay(double amount) {
System.out.println("Card paid: " + amount);
return true;
}
}
// Class — concrete product with state
class Product {
String name;
double price;
Product(String name, double price) {
this.name = name;
this.price = price;
}
}
public class WhenToUseDemo {
public static void checkout(Payment p, Product item) {
p.pay(item.price);
}
public static void main(String[] args) {
checkout(new CardPayment(), new Product("Laptop", 45000));
}
}
5. Multiple Inheritance via Interfaces
Java avoids multiple class inheritance to prevent the diamond problem. A class can implement many interfaces to combine capabilities.
- class A implements X, Y, Z
- Interfaces can extend other interfaces
- Resolve name clashes explicitly
- Prefer small, focused interfaces
interface Flyable { void fly(); }
interface Swimmable { void swim(); }
class Duck implements Flyable, Swimmable {
public void fly() { System.out.println("Flying"); }
public void swim() { System.out.println("Swimming"); }
}
6. Class and Interface Best Practices
Design interfaces to be stable and minimal. Keep implementation details in classes.
- Favor interfaces for public APIs
- Use default methods to evolve interfaces
- Avoid fat interfaces — split if needed
- Document thread-safety expectations
- Program to interface, not implementation
7. Java 8+ Interface Features
Java 8 added default and static methods to interfaces, allowing interface evolution without breaking existing implementers.
- default methods with body in interface
- static methods on interface
- Private methods in interfaces (Java 9+)
- Functional interfaces for lambdas
interface Greeter {
default void greet() { System.out.println("Hello"); }
void sayName();
}
class User implements Greeter {
public void sayName() { System.out.println("Java"); }
}
8. Practice Exercises
Design small hierarchies mixing classes, abstract classes, and interfaces to model real domains.
- Create Shape interface with Circle and Rectangle
- Add abstract Animal with Dog and Cat
- Implement Comparable on a Student class
- Use interface for Sortable behavior
interface Shape { double area(); }
class Square implements Shape {
double side;
Square(double s) { side = s; }
public double area() { return side * side; }
}
9. Summary and Quick Reference
Classes build objects with state; interfaces define contracts. Abstract classes share partial implementation. Choose based on relationship and reuse needs.
- Abstract class — cannot instantiate; may have abstract + concrete methods and fields.
- Abstract method — no body; non-abstract subclass must implement.
- Class — full implementation, constructors, single
extends. - Interface — contract; multiple
implements; program to interface. - Use class for concrete IS-A objects; interface for CAN-DO; abstract class for shared code + forced overrides.
- Java 8+ —
defaultandstaticmethods on interfaces.