00:00

Object-Oriented Programming (OOPs) Concepts in Java

Last updated: 8 min read

Object-oriented programming (OOP) is a way of designing programs around objects: self-contained units that combine data (state) with the operations that work on that data (behaviour). Instead of a long list of functions acting on shared data, an OOP program is a set of objects that collaborate by calling each other's methods.

Java was designed as an object-oriented language from the start. This tutorial introduces classes and objects and the four pillars of OOP (encapsulation, abstraction, inheritance and polymorphism), compares OOP with procedural programming, and links to the detailed tutorial for each concept.

1. What Is Object-Oriented Programming?

OOP models software on real-world things. A banking app has accounts, customers and transactions; a game has players, enemies and weapons. Each becomes a class, and each actual account or player becomes an object of that class.

ConceptMeaningJava feature
ClassBlueprint describing state and behaviourclass, record, enum
ObjectA concrete instance of a classnew
EncapsulationHide internal data; expose controlled operationsprivate fields, methods, access modifiers
AbstractionShow what an object does, hide howAbstract classes, interfaces
InheritanceBuild a new class from an existing oneextends, implements
PolymorphismOne interface, many implementationsMethod overriding and overloading

2. Classes and Objects

A class defines what every object of that type has (fields) and can do (methods). An object is created from the class with new and has three characteristics: state (its field values), behaviour (its methods) and identity (it is distinct from every other object, even one with equal state).

Creating a Java object from a class with the new keyword
ClassAndObject.java
public class ClassAndObject {
    // Class = blueprint: state (fields) + behaviour (methods)
    static class Car {
        String brand;
        int speed;

        Car(String brand) { this.brand = brand; }

        void accelerate(int amount) { speed += amount; }
        void show() { System.out.println(brand + " is moving at " + speed + " km/h"); }
    }

    public static void main(String[] args) {
        Car a = new Car("Tata");      // object 1
        Car b = new Car("Honda");     // object 2: same class, separate state
        a.accelerate(40);
        b.accelerate(65);
        a.accelerate(10);
        a.show();
        b.show();
        System.out.println("Different objects (identity)? " + (a != b));
    }
}
Output
Tata is moving at 50 km/h
Honda is moving at 65 km/h
Different objects (identity)? true

See Classes and Objects in Java for details.

3. The Four Pillars of OOP

One small program can show all four pillars working together:

FourPillars.java
import java.util.List;

public class FourPillars {
    // ABSTRACTION: callers only know "a shape has an area and a name"
    static abstract class Shape {
        private final String name;               // ENCAPSULATION: private state
        Shape(String name) { this.name = name; }
        String name() { return name; }
        abstract double area();                  // what, not how
    }

    // INHERITANCE: Circle and Rectangle are Shapes and reuse name()
    static class Circle extends Shape {
        private final double radius;
        Circle(double radius) {
            super("Circle");
            if (radius <= 0) throw new IllegalArgumentException("radius must be positive");
            this.radius = radius;                // validated before it is stored
        }
        @Override double area() { return Math.PI * radius * radius; }
    }

    static class Rectangle extends Shape {
        private final double width, height;
        Rectangle(double width, double height) {
            super("Rectangle");
            this.width = width; this.height = height;
        }
        @Override double area() { return width * height; }
    }

    public static void main(String[] args) {
        List<Shape> shapes = List.of(new Circle(1.5), new Rectangle(4, 2.5), new Circle(0.5));

        // POLYMORPHISM: one call, the right area() runs for each object
        double total = 0;
        for (Shape s : shapes) {
            System.out.printf("%-9s area = %6.2f%n", s.name(), s.area());
            total += s.area();
        }
        System.out.printf("Total area     = %6.2f%n", total);

        try {
            new Circle(-2);
        } catch (IllegalArgumentException e) {
            System.out.println("Rejected: " + e.getMessage());
        }
    }
}
Output
Circle    area =   7.07
Rectangle area =  10.00
Circle    area =   0.79
Total area     =  17.85
Rejected: radius must be positive

1. Encapsulation

Encapsulation bundles data with the methods that operate on it and hides the data behind private access. Outside code cannot set radius to a negative value, because the only way to create a Circle goes through the constructor's validation. Read more in Encapsulation in Java.

2. Abstraction

Abstraction exposes what an object does and hides how. The loop in main only knows that every Shape has an area(); the formulas stay inside the subclasses. Java supports abstraction with abstract classes and interfaces. See Abstraction in Java.

3. Inheritance

Inheritance lets a class reuse and extend another class. Circle and Rectangle inherit name() from Shape and form an "is-a" relationship: a circle is a shape. See Inheritance in Java.

4. Polymorphism

Polymorphism ("many forms") lets one call behave differently depending on the object. s.area() runs the circle formula for circles and the rectangle formula for rectangles, decided at run time (method overriding). Compile-time polymorphism comes from method overloading. See Polymorphism in Java.

4. Relationships Between Objects

  • Is-a (inheritance): Car extends Vehicle.
  • Has-a (association): one object refers to another. Its forms are aggregation (the part can exist on its own, like a department and its employees) and composition (the part lives and dies with the whole, like a house and its rooms).

A widely followed guideline is "favour composition over inheritance": use inheritance only for a genuine is-a relationship, and compose objects otherwise.

5. OOP vs Procedural Programming

In procedural code, data and functions are separate, so nothing stops any function from putting data into an invalid state. In OOP the object guards its own rules:

ProceduralVsOop.java
public class ProceduralVsOop {
    // Procedural style: data and functions are separate; anyone can change the balance
    static double balance = 1000;
    static void withdraw(double amount) { balance -= amount; }

    // OOP style: data and the rules that protect it live together
    static class Account {
        private double balance;
        Account(double opening) { balance = opening; }
        boolean withdraw(double amount) {
            if (amount <= 0 || amount > balance) return false;
            balance -= amount;
            return true;
        }
        double balance() { return balance; }
    }

    public static void main(String[] args) {
        withdraw(1500);                       // nothing stops an overdraft
        System.out.println("Procedural balance: " + balance);

        Account acc = new Account(1000);
        System.out.println("OOP withdraw 1500 allowed? " + acc.withdraw(1500));
        System.out.println("OOP withdraw 400 allowed?  " + acc.withdraw(400));
        System.out.println("OOP balance: " + acc.balance());
    }
}
Output
Procedural balance: -500.0
OOP withdraw 1500 allowed? false
OOP withdraw 400 allowed?  true
OOP balance: 600.0
AspectProcedural (C)Object-oriented (Java)
Program built fromFunctionsObjects that collaborate
DataOften global or passed around freelyHidden inside objects
Design approachTop-downBottom-up, around domain concepts
ReuseFunction librariesInheritance, composition, interfaces
ChangeData-format changes ripple through many functionsChanges stay inside the class behind its methods

6. Advantages of OOP

  • Modularity: each class has a clear responsibility and can be developed and tested separately.
  • Reusability: classes are reused through inheritance, composition and libraries.
  • Maintainability: encapsulation limits the impact of changes.
  • Extensibility: polymorphism lets you add new types (a Triangle) without changing code that uses Shape.
  • Natural modelling: code mirrors the problem domain, which makes it easier to understand.

OOP also has costs: more up-front design, more classes, and the risk of deep, rigid inheritance hierarchies. Modern Java blends OOP with functional features such as lambdas, streams and records.

7. Is Java a Pure Object-Oriented Language?

No. Java is strongly object-oriented, but not "pure" like Smalltalk, because:

  • It has primitive types (int, double, boolean…) that are not objects.
  • Static members can be used without any object.

Wrapper classes and autoboxing bridge the gap between primitives and objects.

8. Summary

  • OOP organises programs around objects that combine state and behaviour.
  • A class is a blueprint; an object is an instance with state, behaviour and identity.
  • The four pillars are encapsulation, abstraction, inheritance and polymorphism.
  • Objects relate through is-a (inheritance) and has-a (aggregation, composition).
  • Java is object-oriented but not pure, because of primitives and static members.

Related Tutorials