</>
Skip to content
Java lessons (25/47)

Java — Classes and Objects

What is a class?

A class is a blueprint. It defines what data an object holds and what actions it can perform. Think of it like an architectural plan — the plan isn't a house, but you can build houses from it:

class Car {
    String brand;
    int speed;

    void accelerate() {
        speed += 10;
    }

    void brake() {
        speed -= 10;
        if (speed < 0) speed = 0;
    }
}

Car defines the structure (brand, speed) and behavior (accelerate, brake). Every car built from this class will have the same capabilities.

Creating objects

An object is an instance of a class — a concrete thing built from the blueprint:

public class Main {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.brand = "Toyota";
        myCar.speed = 0;

        myCar.accelerate();
        myCar.accelerate();
        System.out.println(myCar.speed);  // 20

        myCar.brake();
        System.out.println(myCar.speed);  // 10
    }
}

new Car() allocates memory for one Car object and returns its address. The variable myCar stores that address — it's a reference to the object, not the object itself.

Instance variables

Variables declared inside a class but outside any method are instance variables:

class Student {
    String name;      // instance variable
    double gpa;       // instance variable
}

Each object gets its own copy. Two Students have separate name and gpa values:

Student alice = new Student();
alice.name = "Alice";
alice.gpa = 3.8;

Student bob = new Student();
bob.name = "Bob";
bob.gpa = 3.5;

System.out.println(alice.name);  // Alice
System.out.println(bob.name);    // Bob

Constructors

A constructor runs automatically when you create an object. Use it to initialize state:

class Car {
    String brand;
    int speed;

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

Car myCar = new Car("Honda");
System.out.println(myCar.brand);  // Honda

The this keyword refers to the current object — it distinguishes instance variables from parameters when names collide.

Default constructor

If you don't write any constructor, Java provides one automatically with no parameters. Once you define any constructor, the default one disappears.

Multiple constructors

class Student {
    String name;
    int age;

    Student(String name) {
        this.name = name;
        this.age = 0;
    }

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Student s1 = new Student("Ada");        // age defaults to 0
Student s2 = new Student("Grace", 30);  // age is 30

This pattern — overloading constructors — lets callers choose how much detail to provide.

Methods on objects

Methods that operate on instance data make objects useful:

class BankAccount {
    String owner;
    double balance;

    BankAccount(String owner, double initialDeposit) {
        this.owner = owner;
        this.balance = initialDeposit;
    }

    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.printf("Deposited $%.2f%n", amount);
        }
    }

    void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.printf("Withdrew $%.2f%n", amount);
        } else {
            System.out.println("Insufficient funds.");
        }
    }

    void displayBalance() {
        System.out.printf("%s's balance: $%.2f%n", owner, balance);
    }
}

BankAccount acc = new BankAccount("Ada", 1000);
acc.deposit(500);
acc.withdraw(200);
acc.displayBalance();  // Ada's balance: $1300.00

Each method modifies the object's state and provides a clean interface for interacting with it.

Encapsulation — hiding internals

Direct access to instance variables is risky — anyone can set invalid values. Use private access and provide methods:

class Thermometer {
    private double celsius;

    void setCelsius(double temp) {
        if (temp >= -273.15) {  // absolute zero check
            celsius = temp;
        } else {
            System.out.println("Invalid temperature.");
        }
    }

    double getCelsius() {
        return celsius;
    }

    double getFahrenheit() {
        return celsius * 9.0 / 5.0 + 32;
    }
}

private restricts access to within the class. Public methods (setCelsius, getCelsius, getFahrenheit) provide controlled access. This is encapsulation — the foundation of reliable object-oriented code.

The toString method

Every Java object inherits a toString() method. Override it to get meaningful output:

class Student {
    String name;
    int age;

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{name='" + name + "', age=" + age + "}";
    }
}

Student s = new Student("Ada", 25);
System.out.println(s);  // Student{name='Ada', age=25}

Without the override, System.out.println(s) prints the memory address — not useful. The @Override annotation tells the compiler you're replacing a parent method.

Comparing objects

The == operator compares references (memory addresses), not content:

Student a = new Student("Ada", 25);
Student b = new Student("Ada", 25);

System.out.println(a == b);       // false — different objects
System.out.println(a.equals(b));  // false — default equals checks references

Override equals() for meaningful comparison:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof Student)) return false;
    Student other = (Student) obj;
    return this.age == other.age && this.name.equals(other.name);
}

Thinking in objects

The real shift in Java isn't syntax — it's mindset. Instead of writing procedures that manipulate data, you design objects that know things and do things:

// Procedural thinking
String[] names = {"Ada", "Grace"};
int[] scores = {95, 88};

// Object thinking
Student ada = new Student("Ada", 95);
Student grace = new Student("Grace", 88);

Objects bundle data with behavior. As programs grow, this organization keeps complexity manageable.

Mini Practice

  1. Create a Book class with title, author, and pages — add a constructor and a describe() method
  2. Add a read(pages) method to Book that tracks how many pages are left
  3. Override toString() so System.out.println(book) prints a readable summary
  4. Create two Book objects and compare them using == then equals()
  5. Build a Calculator class with methods for add, subtract, multiply, and divide — handle division by zero

Next: constructors — initializing objects →

Related Topics

Frequently Asked Questions about Classes and Objects

What is Classes and Objects in Java?

Classes and Objects is a fundamental concept in Java. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Classes and Objects?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Classes and Objects.

Why is Classes and Objects important in Java?

Classes and Objects is essential for Java development. Understanding this concept will help you write better code and solve real-world problems more effectively.