Java Objects

Su Suriya Ravichandran Updated 14 Nov 2026
8 min read ·Lesson 43 of 133

An object is an instance of a class: a concrete thing in memory, with its own values for the fields the class defines. A class is written once; objects are created from it as many times as the program needs. Knowing how objects are created, referenced, compared, and destroyed explains a large share of Java's everyday behavior.

Creating an Object

public class Point {
    int x;
    int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
Point p = new Point(3, 4);

This one line does four things:

  1. Declares a variable p of type Point.
  2. Allocates memory on the heap for a new Point object, with its fields set to defaults (0).
  3. Runs the constructor, which assigns x = 3 and y = 4.
  4. Stores a reference to the new object in p.

The new keyword is what creates the object. Declaring a variable alone creates nothing:

Point q;               // a variable that can refer to a Point; no object exists
q.x = 1;               // compile error if q is a local variable: not initialized

Accessing Fields and Methods

The dot operator reaches an object's members:

Point p = new Point(3, 4);
System.out.println(p.x);          // 3
p.y = 10;                         // only possible because y is not private here

With a well-encapsulated class, you call methods instead of touching fields:

public class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) { this.x = x; this.y = y; }

    public int getX() { return x; }
    public int getY() { return y; }

    public double distanceTo(Point other) {
        int dx = x - other.x;
        int dy = y - other.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
}
Point a = new Point(0, 0);
Point b = new Point(3, 4);
System.out.println(a.distanceTo(b));   // 5.0

Inside distanceTo, x refers to the field of the object the method was called on (a), and other.x refers to the field of the argument (b). A class's methods can access private fields of any object of that class; privacy is enforced per class, not per object.

Each Object Has Its Own State

public class Counter {
    private int count;
    public void increment() { count++; }
    public int get() { return count; }
}
Counter pageViews = new Counter();
Counter downloads = new Counter();

pageViews.increment();
pageViews.increment();
downloads.increment();

System.out.println(pageViews.get());   // 2
System.out.println(downloads.get());   // 1

Both objects run the same increment code, but each changes only its own count. This is the essential difference between instance fields and static fields: a static field would be shared, and both would report 3.

Variables Hold References, Not Objects

An object variable does not contain the object. It contains a reference: a pointer the JVM uses to find the object on the heap.

Counter a = new Counter();
Counter b = a;              // copies the reference: both refer to the SAME object

b.increment();
System.out.println(a.get());   // 1: the change is visible through a
a ──┐
    ├──►  Counter { count = 1 }
b ──┘

Assignment copies the reference, never the object. To get an independent copy, you must create a new object, for example through a copy constructor or a method that builds one.

The same rule applies when passing objects to methods. The method receives a copy of the reference, so it can modify the object the caller passed in:

static void resetTo(Counter c, int times) {
    c.increment();          // affects the caller's object
}

null: A Reference to Nothing

A reference variable can hold null, meaning it refers to no object:

Point p = null;
System.out.println(p == null);   // true
p.getX();                        // NullPointerException

Calling a method or reading a field through null throws NullPointerException. Modern JVMs explain exactly which reference was null:

Exception in thread "main" java.lang.NullPointerException:
    Cannot invoke "Point.getX()" because "p" is null

Fields of reference type default to null, which is why an object created without initializing such a field can fail later. Initialize fields in the constructor, validate parameters with Objects.requireNonNull, and return empty collections or Optional rather than null where possible.

Comparing Objects: == Versus equals

== on references asks: are these the same object?

equals asks: are these objects equivalent?, according to the class's own definition.

String s1 = new String("java");
String s2 = new String("java");

System.out.println(s1 == s2);        // false: two separate objects
System.out.println(s1.equals(s2));   // true: same characters

For your own classes, equals inherited from Object behaves exactly like == until you override it:

Point a = new Point(1, 2);
Point b = new Point(1, 2);
System.out.println(a.equals(b));   // false with the inherited Object.equals

To compare by value, override equals and hashCode together:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Point other)) return false;
    return x == other.x && y == other.y;
}

@Override
public int hashCode() {
    return Objects.hash(x, y);
}

hashCode must be overridden whenever equals is, because hash-based collections (HashMap, HashSet) first compare hash codes to decide where an object belongs. Two equal objects with different hash codes would be treated as different keys. IDEs generate both methods correctly, and records generate them automatically:

record Point(int x, int y) {}

System.out.println(new Point(1, 2).equals(new Point(1, 2)));   // true

Objects and the Object Class

Every class extends java.lang.Object, directly or indirectly. So every object has these methods:

MethodDefault behaviorCommonly overridden?
toString()Class name + @ + hash in hexYes, for readable output
equals(Object)Same as ==Yes, for value comparison
hashCode()Identity-based numberYes, whenever equals is
getClass()Returns the runtime classNo (it is final)

getClass() reveals the object's actual class, which may be more specific than the variable's declared type:

Object o = "hello";
System.out.println(o.getClass().getName());   // java.lang.String

Arrays and Collections of Objects

An array or list of objects holds references:

Point[] corners = new Point[4];       // four null references, no Points yet
corners[0] = new Point(0, 0);
corners[1] = new Point(5, 0);

List<Point> path = new ArrayList<>();
path.add(new Point(0, 0));
path.add(new Point(3, 4));
path.add(new Point(6, 8));

double length = 0;
for (int i = 1; i < path.size(); i++) {
    length += path.get(i - 1).distanceTo(path.get(i));
}
System.out.println(length);   // 10.0

new Point[4] creates an array, not four points. Each slot starts as null and must be assigned an object before use.

Object Lifetime and Garbage Collection

An object lives as long as it is reachable: as long as some chain of references from active code leads to it. When nothing refers to it anymore, it becomes eligible for garbage collection, and the JVM reclaims its memory automatically.

Point p = new Point(1, 1);   // object A, referenced by p
p = new Point(2, 2);         // object B; nothing refers to A anymore
p = null;                    // nothing refers to B either

After the second line, object A is unreachable. After the third, so is B. You never free memory explicitly, and there are no destructors. Objects that hold external resources (files, sockets, database connections) are closed explicitly, usually with try-with-resources, rather than relying on garbage collection.

Anonymous and Temporary Objects

An object does not need to be stored in a variable. It can be created and used immediately:

System.out.println(new Point(3, 4).distanceTo(new Point(0, 0)));   // 5.0
String upper = new StringBuilder("abc").reverse().toString().toUpperCase();   // "CBA"

These objects are unreachable as soon as the expression finishes and are collected. Method chaining like the StringBuilder example works because each method returns an object on which the next method is called.

Immutable Objects

An immutable object's state cannot change after it is constructed. String, Integer, LocalDate, BigDecimal, and records are immutable.

LocalDate d = LocalDate.of(2026, 11, 10);
d.plusDays(1);                    // returns a NEW LocalDate; d is unchanged
LocalDate next = d.plusDays(1);   // 2026-11-11

Immutable objects can be shared freely, because no one can modify them unexpectedly; they are automatically thread-safe and make reliable HashMap keys. Making a class immutable requires private final fields, no methods that modify state, and care with mutable fields such as lists (store and return copies).

Practical Example: Shopping Cart

import java.util.ArrayList;
import java.util.List;

public class CartDemo {
    record Product(String name, double price) {}

    static class LineItem {
        private final Product product;
        private int quantity;

        LineItem(Product product, int quantity) {
            this.product = product;
            this.quantity = quantity;
        }

        double total() { return product.price() * quantity; }
    }

    static class Cart {
        private final List<LineItem> items = new ArrayList<>();

        void add(Product p, int qty) {
            for (LineItem item : items) {
                if (item.product.equals(p)) {     // record equality: same name and price
                    item.quantity += qty;
                    return;
                }
            }
            items.add(new LineItem(p, qty));
        }

        double total() {
            double sum = 0;
            for (LineItem item : items) sum += item.total();
            return sum;
        }

        int itemCount() { return items.size(); }
    }

    public static void main(String[] args) {
        Product pen = new Product("Pen", 25);
        Product book = new Product("Notebook", 120);

        Cart mine = new Cart();
        Cart yours = new Cart();

        mine.add(pen, 3);
        mine.add(book, 1);
        mine.add(new Product("Pen", 25), 2);    // a different object, but equal

        yours.add(book, 4);

        System.out.println("Mine:  " + mine.itemCount() + " lines, total " + mine.total());
        System.out.println("Yours: " + yours.itemCount() + " lines, total " + yours.total());
    }
}

Output:

Mine:  2 lines, total 245.0
Yours: 1 lines, total 480.0

Two Cart objects maintain completely separate item lists. The same book object is referenced by both carts' line items, which is safe because records are immutable. The third add call passes a new Product object, but equals (generated by the record) recognizes it as the same product, so the quantity of the existing pen line grows to 5 instead of a duplicate line being added. With == in place of equals, the cart would show three lines.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Java Objects and get answers drawn from it.

Signed-in readers only.