Introduction to Object-Oriented Programming

So far, you’ve written programs using variables, methods, and data structures. That approach works for small programs. But as projects grow, organizing code becomes difficult. Object-oriented programming (OOP) provides a way to structure larger programs by modeling them as interacting objects.

Java was designed from the ground up as an object-oriented language. Understanding OOP isn’t optional for Java developers. It’s fundamental to how the language works.

What is Object-Oriented Programming?

OOP organizes code around objects rather than actions. An object combines data (what it knows) and behavior (what it can do) into a single unit.

Think about a car. A car has data: color, speed, fuel level. A car has behaviors: accelerate, brake, turn. In OOP, you’d model a car as an object that bundles these properties and actions together.

This mirrors how we think about the real world. We don’t think of “accelerating” as a free-floating action. We think of a specific car accelerating. OOP lets you write code that reflects this natural way of thinking.

Classes and Objects

A class is a blueprint. An object is a thing built from that blueprint.

Consider a cookie cutter. The cutter itself is like a class. It defines the shape. Each cookie you make with it is an object. All cookies share the same shape, but each is a separate cookie. You can frost one without affecting the others.

// The class (blueprint)
public class Dog {
    String name;
    int age;
    
    void bark() {
        System.out.println(name + " says woof!");
    }
}

// Creating objects (instances)
Dog dog1 = new Dog();
dog1.name = "Buddy";
dog1.age = 3;

Dog dog2 = new Dog();
dog2.name = "Max";
dog2.age = 5;

The Dog class defines what all dogs have: a name, an age, and the ability to bark. Each Dog object is a specific dog with its own name and age.

You can create as many objects as you need from one class. Each object maintains its own separate data.

Why OOP Matters

OOP offers several advantages as programs grow.

Organization

Related data and behavior stay together. Instead of separate arrays for dog names, dog ages, and functions that operate on dogs, everything lives in the Dog class. When you need to work with dogs, you know where to look.

Reusability

Write a class once, use it anywhere. A well-designed class can be used across multiple projects. Java’s standard library provides thousands of pre-built classes you use every day: String, ArrayList, Scanner.

Modularity

Objects interact through defined interfaces. You can change how an object works internally without affecting code that uses it, as long as the interface stays the same. This makes large systems easier to maintain and modify.

Modeling

OOP lets you model real-world concepts directly. A banking application has Account, Customer, and Transaction objects. A game has Player, Enemy, and Weapon objects. The code structure mirrors the problem domain.

The Four Pillars of OOP

Four core concepts define object-oriented programming. We’ll introduce them here and explore each in depth in the following tutorials.

Encapsulation

Encapsulation bundles data with the methods that operate on it and restricts direct access to some components. Instead of letting any code change an object’s data directly, you control access through methods.

public class BankAccount {
    private double balance;  // Hidden from outside
    
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
    
    public double getBalance() {
        return balance;
    }
}

Outside code can’t set balance to a negative number by accident. It must use deposit(), which validates the input. The object protects its own data.

Inheritance

Inheritance lets a class inherit properties and behaviors from another class. The child class gets everything the parent has, plus it can add its own features or modify inherited ones.

public class Animal {
    String name;
    
    void eat() {
        System.out.println(name + " is eating");
    }
}

public class Dog extends Animal {
    void bark() {
        System.out.println(name + " says woof!");
    }
}

// Dog has both eat() from Animal and bark() from Dog
Dog dog = new Dog();
dog.name = "Buddy";
dog.eat();   // Inherited
dog.bark();  // Own method

Inheritance creates an “is-a” relationship. A Dog is an Animal. This lets you reuse code and build hierarchies of related classes.

Polymorphism

Polymorphism means “many forms.” It lets you treat objects of different classes through a common interface. A method can work with any object that fits the expected type, regardless of its specific class.

public class Animal {
    void makeSound() {
        System.out.println("Some sound");
    }
}

public class Dog extends Animal {
    void makeSound() {
        System.out.println("Woof!");
    }
}

public class Cat extends Animal {
    void makeSound() {
        System.out.println("Meow!");
    }
}

// Polymorphism in action
Animal myPet = new Dog();
myPet.makeSound();  // Prints "Woof!"

myPet = new Cat();
myPet.makeSound();  // Prints "Meow!"

The variable myPet is declared as Animal but can hold any Animal subclass. When you call makeSound(), Java runs the version defined by the actual object, not the declared type.

Abstraction

Abstraction hides complex implementation details and exposes only what’s necessary. Users of a class don’t need to know how it works internally. They just need to know what it does.

When you call ArrayList.add(), you don’t think about how ArrayList manages memory or resizes its internal array. You just add an element. That complexity is abstracted away.

Abstraction is achieved through well-designed public interfaces and by hiding implementation details with access modifiers.

Objects You’ve Already Used

You’ve been using objects since your first Java program.

String is a class. Every string you create is a String object with methods like length(), toUpperCase(), and substring().

String message = "Hello";  // message is a String object
int len = message.length();  // Calling a method on the object

Scanner is a class. When you create a Scanner, you’re creating an object that knows how to read input.

Scanner scanner = new Scanner(System.in);  // scanner is an object
String input = scanner.nextLine();  // Calling a method

ArrayList is a class. Each ArrayList you create is an object managing its own list of elements.

ArrayList<String> list = new ArrayList<>();  // list is an object
list.add("item");  // Calling a method

The pattern is consistent: create an object, then call its methods. Now you’ll learn to create your own classes.

Procedural vs Object-Oriented

Compare two approaches to the same problem: managing student grades.

Procedural Approach

// Data in separate arrays
String[] names = {"Alice", "Bob", "Charlie"};
int[] grades = {85, 92, 78};

// Functions operate on the data
public static double getAverage(int[] grades) {
    int sum = 0;
    for (int g : grades) sum += g;
    return (double) sum / grades.length;
}

public static void printStudent(String[] names, int[] grades, int index) {
    System.out.println(names[index] + ": " + grades[index]);
}

Data and functions are separate. Adding a new field (like student ID) means modifying multiple arrays and updating every function.

Object-Oriented Approach

public class Student {
    String name;
    int grade;
    
    public Student(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }
    
    public void print() {
        System.out.println(name + ": " + grade);
    }
}

// Using the class
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("Alice", 85));
students.add(new Student("Bob", 92));
students.add(new Student("Charlie", 78));

for (Student s : students) {
    s.print();
}

Each student is a self-contained object. Adding a student ID means adding one field to the Student class. The change is localized.

When to Use OOP

OOP isn’t always necessary. For a 50-line script that processes a file, classes might be overkill. But as complexity grows, OOP pays off.

Good candidates for OOP:

  • Programs with multiple related entities (users, products, orders)
  • Code that will be extended or modified over time
  • Projects with multiple developers
  • Applications that model real-world concepts

Maybe skip OOP for:

  • Quick scripts and one-off utilities
  • Simple data processing tasks
  • Programs under 100 lines

In practice, most Java programs beyond trivial examples benefit from at least some object-oriented design.

Key Terminology

Terms you’ll encounter throughout the OOP tutorials:

Class: A blueprint defining the structure and behavior of objects.

Object: An instance of a class. A concrete thing created from the blueprint.

Instance: Another word for object. “Creating an instance” means creating an object.

Field: A variable declared inside a class. Also called instance variable or attribute.

Method: A function defined inside a class.

Constructor: A special method that runs when an object is created.

Instantiation: The process of creating an object from a class using new.

What’s Next

This tutorial introduced the concepts. The next tutorial gets practical. You’ll create your own classes, define fields and methods, and instantiate objects. By the end, you’ll be writing object-oriented Java code.


Related: ArrayList in Java | Java Classes and Objects

Sources

  • Oracle. “Object-Oriented Programming Concepts.” The Java Tutorials. docs.oracle.com
  • Bloch, Joshua. “Effective Java.” 3rd Edition. Addison-Wesley, 2018.
Scroll to Top