Skip to main content

Object-Oriented Programming in Java

Object-Oriented Programming (OOP) is the foundation of Java. Everything in Java revolves around objects and classes, making it one of the most naturally OOP-friendly languages available.

Core Conceptsโ€‹

1. Class & Objectโ€‹

A class is a blueprint. An object is an instance of that blueprint.

public class Car {
String brand;
int year;

public Car(String brand, int year) {
this.brand = brand;
this.year = year;
}

public void drive() {
System.out.println(brand + " is driving!");
}
}

// Creating an object
Car myCar = new Car("Toyota", 2022);
myCar.drive(); // Toyota is driving!

2. Encapsulationโ€‹

Encapsulation means bundling data (fields) and behavior (methods) together, while restricting direct access to internal state using access modifiers.

Key Idea

Hide the data, expose the behavior.

public class BankAccount {
private double balance; // hidden from outside

public double getBalance() {
return balance;
}

public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}

public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}

Access Modifiers:

ModifierSame ClassSame PackageSubclassEverywhere
privateโœ…โŒโŒโŒ
(default)โœ…โœ…โŒโŒ
protectedโœ…โœ…โœ…โŒ
publicโœ…โœ…โœ…โœ…
Spring Tip

Spring beans rely heavily on encapsulation. @Service, @Repository, and @Component classes expose only what's needed through public methods or interfaces.


3. Inheritanceโ€‹

Inheritance allows a class to acquire properties and methods from a parent class using the extends keyword.

public class Animal {
protected String name;

public Animal(String name) {
this.name = name;
}

public void makeSound() {
System.out.println(name + " makes a sound.");
}
}

public class Dog extends Animal {
public Dog(String name) {
super(name); // call parent constructor
}

@Override
public void makeSound() {
System.out.println(name + " barks!");
}
}

Animal dog = new Dog("Rex");
dog.makeSound(); // Rex barks!

Key rules:

  • Java supports single inheritance only (one parent class)
  • Use super to access parent class members
  • @Override annotation signals an intentional method override โ€” always use it!
warning

Avoid deep inheritance chains (more than 2โ€“3 levels). They make code harder to understand and maintain. Prefer composition over inheritance when possible.


4. Polymorphismโ€‹

Polymorphism means "many forms" โ€” the same interface can behave differently depending on the actual object.

Compile-time (Method Overloading)โ€‹

public class Calculator {
public int add(int a, int b) {
return a + b;
}

public double add(double a, double b) { // same name, different params
return a + b;
}
}

Runtime (Method Overriding)โ€‹

public class Shape {
public double area() {
return 0;
}
}

public class Circle extends Shape {
private double radius;

public Circle(double radius) {
this.radius = radius;
}

@Override
public double area() {
return Math.PI * radius * radius;
}
}

public class Rectangle extends Shape {
private double width, height;

public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}

@Override
public double area() {
return width * height;
}
}

// Polymorphic behavior
List<Shape> shapes = List.of(new Circle(5), new Rectangle(4, 6));
shapes.forEach(s -> System.out.println(s.area()));
Spring Tip

Polymorphism powers Spring's dependency injection. You program to an interface, and Spring injects the correct implementation at runtime.


5. Abstractionโ€‹

Abstraction hides implementation details and exposes only the essential features. Java achieves this through abstract classes and interfaces.

Abstract Classโ€‹

public abstract class Vehicle {
protected String model;

public Vehicle(String model) {
this.model = model;
}

public abstract void fuelUp(); // must be implemented by subclass

public void startEngine() { // shared behavior
System.out.println(model + " engine started.");
}
}

public class ElectricCar extends Vehicle {
public ElectricCar(String model) {
super(model);
}

@Override
public void fuelUp() {
System.out.println(model + " is charging...");
}
}

Interfaceโ€‹

public interface Payable {
void processPayment(double amount); // implicitly public & abstract

default void printReceipt() { // default method (Java 8+)
System.out.println("Payment processed.");
}
}

public class CreditCardPayment implements Payable {
@Override
public void processPayment(double amount) {
System.out.println("Charging $" + amount + " to credit card.");
}
}

Abstract Class vs Interface:

FeatureAbstract ClassInterface
InstantiationโŒ CannotโŒ Cannot
Multiple inheritanceโŒ Noโœ… Yes (implements A, B)
Constructorโœ… YesโŒ No
FieldsAny typepublic static final only
MethodsAbstract + concreteAbstract + default/static
Spring Tip

Interfaces are everywhere in Spring. JpaRepository, ApplicationContext, BeanFactory โ€” you always code to the interface, letting Spring provide the implementation.


SOLID Principlesโ€‹

These 5 principles guide writing clean, maintainable OOP code.

PrincipleDescription
Single ResponsibilityA class should have only one reason to change
Open/ClosedOpen for extension, closed for modification
Liskov SubstitutionSubclasses must be substitutable for their base class
Interface SegregationPrefer small, specific interfaces over large, general ones
Dependency InversionDepend on abstractions, not concrete implementations
// โœ… Dependency Inversion in Spring
@Service
public class OrderService {
private final PaymentGateway paymentGateway; // interface, not implementation

public OrderService(PaymentGateway paymentGateway) { // injected by Spring
this.paymentGateway = paymentGateway;
}
}
note

Following SOLID principles naturally leads to better Spring application design โ€” especially Dependency Inversion, which is the backbone of Spring's IoC container.


Quick Referenceโ€‹

OOP in Java
โ”œโ”€โ”€ Encapsulation โ†’ private fields + public getters/setters
โ”œโ”€โ”€ Inheritance โ†’ extends (single), super keyword
โ”œโ”€โ”€ Polymorphism โ†’ overloading (compile-time), overriding (runtime)
โ””โ”€โ”€ Abstraction โ†’ abstract class, interface

Further Readingโ€‹


Advanced Editorial Pass: OOP as Boundary Design, Not Boilerplateโ€‹

Architectural Lensโ€‹

  • OOP value comes from explicit boundaries, invariants, and change isolation.
  • Encapsulation should protect business rules, not merely hide fields.
  • Composition strategy should reflect domain volatility and extension pressure.

Common Misuse Patternsโ€‹

  • Inheritance used for code reuse instead of semantic substitutability.
  • Anemic models that move all behavior into service layers.
  • Over-abstracted class hierarchies without real variation.

Senior Heuristicsโ€‹

  1. Keep domain invariants close to the data they constrain.
  2. Prefer composition when behavior variation is runtime-driven.
  3. Audit object responsibilities regularly to prevent god objects.

Compare Nextโ€‹