Skip to content
elephantoo

Classes & objects

Lesson 10 of 43 15 min read

Fields, methods, creating objects with new, references, null and toString.


So far we have written everything as static methods working on primitives, strings and arrays. That works for small programs, but real software models things: customers, orders, bank accounts, game characters. Object-oriented programming (OOP) lets you bundle the data about a thing together with the behaviour that operates on it.

Classes and objects#

  • A class is a blueprint. It describes what data a thing has (fields) and what it can do (methods).
  • An object is a concrete instance built from that blueprint. You can create as many objects from one class as you like, each with its own data.

Think of Car as a class: every car has a colour, a model and a speed, and can accelerate and brake. Your red hatchback and my blue SUV are two objects of that class.

Your first class#

Book.java
public class Book {
    // fields (state): each Book object gets its own copy
    String title;
    String author;
    int pages;

    // methods (behaviour)
    String label() {
        return title + " by " + author;
    }

    boolean isLong() {
        return pages > 400;
    }
}

These are instance fields and methods: they belong to each individual object. Notice there is no static keyword. Inside label(), title means "the title of the book this method was called on".

Creating and using objects#

new creates an object; the dot . accesses its fields and methods:

Library.java
public class Library {
    public static void main(String[] args) {
        Book a = new Book();
        a.title = "Dune";
        a.author = "Frank Herbert";
        a.pages = 688;

        Book b = new Book();
        b.title = "The Hobbit";
        b.author = "J.R.R. Tolkien";
        b.pages = 310;

        System.out.println(a.label());
        System.out.println(b.label());
        System.out.println(a.isLong() + " " + b.isLong());
    }
}

class Book {
    String title;
    String author;
    int pages;

    String label() {
        return title + " by " + author;
    }

    boolean isLong() {
        return pages > 400;
    }
}
Output
Dune by Frank Herbert
The Hobbit by J.R.R. Tolkien
true false

Each new Book() creates an independent object in memory. Changing a never affects b.

One file, several classes: a .java file may contain several top-level classes, but at most one can be public, and it must match the filename. That is handy for small examples like the one above. In real projects, put each class in its own file (Book.java, Library.java) in the same folder, and compile with javac *.java.

Default values of fields#

Unlike local variables, fields get default values automatically when an object is created:

Field typeDefault
int, long, double...0 / 0.0
booleanfalse
char'\u0000'
any object type (String, arrays, Book)null

So a fresh new Book() has title == null and pages == 0. Setting every field by hand after new is tedious and error-prone. The next lesson introduces constructors, which initialise an object in one step.

References: variables point to objects#

A variable of a class type does not contain the object itself; it holds a reference (an arrow) to an object living on the heap:

References.java
public class References {
    public static void main(String[] args) {
        Counter c1 = new Counter();
        Counter c2 = c1;          // copy the arrow, NOT the object
        c2.increment();
        c2.increment();
        System.out.println(c1.count);   // same object!

        Counter c3 = new Counter();
        System.out.println(c3.count);   // a separate object
        System.out.println(c1 == c2);   // same object?
        System.out.println(c1 == c3);
    }
}

class Counter {
    int count;

    void increment() {
        count++;
    }
}
Output
2
0
true
false
Output
c1 ──┐
     ├──► [Counter count=2]
c2 ──┘
c3 ─────► [Counter count=0]

== on references asks "do these point to the same object?". Whether two different objects are "equal" in content is decided by the equals method, which you will learn to write in the equals() & hashCode() lesson.

null and NullPointerException#

A reference variable can hold null, meaning "no object". Calling a method or reading a field through null throws a NullPointerException (NPE), the most famous runtime error in Java:

Java
Book missing = null;
System.out.println(missing.title);   // throws NullPointerException

Modern JVMs give helpful messages that name the culprit:

Output
Exception in thread "main" java.lang.NullPointerException: Cannot read field "title" because "missing" is null

Protect against it by checking if (missing != null), by always initialising fields, and later with Optional.

Methods can use and change state#

Methods are where the behaviour lives. They can read fields, change them, take parameters and return results:

BankDemo.java
public class BankDemo {
    public static void main(String[] args) {
        Account acc = new Account();
        acc.owner = "Meera";
        acc.deposit(5000);
        acc.withdraw(1200);
        acc.withdraw(10000);
        System.out.println(acc.summary());
    }
}

class Account {
    String owner;
    double balance;

    void deposit(double amount) {
        balance += amount;
    }

    void withdraw(double amount) {
        if (amount > balance) {
            System.out.println("Insufficient funds for " + amount);
            return;
        }
        balance -= amount;
    }

    String summary() {
        return owner + " has " + balance;
    }
}
Output
Insufficient funds for 10000.0
Meera has 3800.0

Code outside the class can still write acc.balance = -999; and bypass the checks in withdraw. The encapsulation lesson shows how private fields prevent that.

toString(): a readable description#

Every class secretly extends Object, which provides a toString() method. Printing an object calls it. The default output is not very helpful:

Output
Book@1b6d3586

Override it to describe your object:

Point.java
public class Point {
    int x;
    int y;

    @Override
    public String toString() {
        return "Point(" + x + ", " + y + ")";
    }

    double distanceToOrigin() {
        return Math.sqrt(x * x + y * y);
    }

    public static void main(String[] args) {
        Point p = new Point();
        p.x = 3;
        p.y = 4;
        System.out.println(p);                    // calls p.toString()
        System.out.println("Distance: " + p.distanceToOrigin());
    }
}
Output
Point(3, 4)
Distance: 5.0

@Override asks the compiler to verify you really are overriding a parent method. It will catch typos like tostring(). You will learn more in the inheritance and polymorphism lessons.

Objects working together#

Fields can hold other objects, and methods can take objects as parameters. This is how real systems are built:

Shop.java
public class Shop {
    public static void main(String[] args) {
        Product pen = new Product();
        pen.name = "Pen";
        pen.price = 25;

        Product book = new Product();
        book.name = "Notebook";
        book.price = 60;

        Cart cart = new Cart();
        cart.add(pen, 4);
        cart.add(book, 2);
        System.out.println("Items: " + cart.itemCount + ", total: " + cart.total);
    }
}

class Product {
    String name;
    double price;
}

class Cart {
    int itemCount;
    double total;

    void add(Product p, int qty) {
        itemCount += qty;
        total += p.price * qty;
        System.out.println("Added " + qty + " x " + p.name);
    }
}
Output
Added 4 x Pen
Added 2 x Notebook
Items: 6, total: 220.0

The four pillars of OOP#

You will study each in its own lesson:

  1. Encapsulation: hide internal data behind a public interface.
  2. Inheritance: build specialised classes from general ones.
  3. Polymorphism: treat different objects through a common type, with each responding in its own way.
  4. Abstraction: expose what something does, hiding how.

Common mistakes#

  • Forgetting new: Book b; b.title = "x"; does not compile, because b was never assigned an object.
  • Confusing the class with an object: Book.title does not work for an instance field; you need an object, as in b.title.
  • Assuming b = a copies an object.
  • Calling instance methods from static main without an object.

What's next#

Setting fields one by one after new is clumsy. Next you will learn constructors and the this keyword to create fully initialised objects in one line.

Check your understanding

Quick quiz

0/3 answered
  1. 1.What is an object?

  2. 2.After Dog a = new Dog("Rex"); Dog b = a; b.name = "Max";, what is a.name?

  3. 3.What happens when you call a method on a variable that holds null?

Finished reading?

Mark this lesson complete to track your progress.