Skip to content
Classes
step 1/7

Reading — step 1 of 7

Learn

~4 min readMethods and Classes

Classes are the heart of Java's object-oriented model. A class bundles fields (data/state) with methods (behavior). An object (or instance) is a specific thing built from the class blueprint. Java's class syntax is more verbose than Python or JavaScript — but every part has a reason.

Defining a class

public class Point {
    int x;          // field
    int y;          // field
    
    Point(int x, int y) {       // constructor
        this.x = x;
        this.y = y;
    }
    
    double distance(Point other) {     // method
        int dx = x - other.x;
        int dy = y - other.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
}

Five parts of the anatomy:

  1. public — access modifier (more on these below).
  2. class Point — the class declaration. PascalCase by convention.
  3. Fields — variables that belong to each instance.
  4. Constructor — special method (same name as class, no return type) that runs when you new an instance.
  5. Methods — operations on the object.

Creating instances with new

Point p = new Point(3, 4);
System.out.println(p.x);                          // 3
System.out.println(p.distance(new Point(0, 0)));  // 5.0

The new keyword:

  1. Allocates memory for a new Point.
  2. Calls the constructor.
  3. Returns a reference to the new object.

this — the current instance

Inside instance methods, this refers to the object the method was called on:

public class Point {
    int x, y;
    Point(int x, int y) {
        this.x = x;     // this.x is the field; x is the parameter
        this.y = y;
    }
}

Without this, x = x would just assign the parameter to itself. You need this.x to disambiguate field from parameter.

When there's no naming clash, this is optional — but many style guides write it explicitly for clarity.

Access modifiers

Control visibility:

public class Point {
    public int x;            // accessible from anywhere
    private int y;           // accessible only within Point
    protected int z;         // accessible within package + subclasses
    int w;                   // package-private (default — no modifier)
}

Convention: fields private, methods public (or whatever access they need). Use getter/setter methods to expose data:

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

This is encapsulation — hide implementation details, expose a controlled interface.

Constructors — overloading

public class Point {
    int x, y;
    
    Point() {                  // no-arg constructor
        this(0, 0);             // calls the other constructor
    }
    
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

Point origin = new Point();          // (0, 0)
Point p = new Point(3, 4);

Multiple constructors with different parameter lists. this(...) from inside a constructor calls another constructor of the same class.

static — belongs to the class, not an instance

public class Counter {
    static int totalCreated = 0;     // shared across ALL instances
    int id;                           // per-instance
    
    Counter() {
        totalCreated++;
        id = totalCreated;
    }
}

new Counter();              // totalCreated = 1
new Counter();              // totalCreated = 2
System.out.println(Counter.totalCreated);   // 2 — accessed via class name

static members belong to the class, not any specific instance. Static methods can be called via the class: Math.sqrt(2).

record — concise data classes (Java 16+)

record Point(int x, int y) {}

Point p = new Point(3, 4);
System.out.println(p.x());         // 3 — auto-generated accessor
System.out.println(p);              // Point[x=3, y=4]
System.out.println(p.equals(new Point(3, 4)));   // true

A record auto-generates: constructor, accessors (x(), y()), equals, hashCode, toString. For immutable data carriers, this saves dozens of lines vs a normal class.

toString(), equals(), hashCode()

Every class inherits these from Object. Default implementations are usually wrong:

class Point { int x, y; ... }

Point a = new Point(3, 4);
Point b = new Point(3, 4);
System.out.println(a.equals(b));    // false — default checks reference identity

Override them when needed (or use record, which generates correct versions for free).

Common mistakes

  • Forgetting this.field = field in constructors with same-name parameters.
  • Public fields everywhere — breaks encapsulation. Use private + getters.
  • Modifying fields without this. when there's a parameter shadowing — assigns to itself, not the field.
  • Comparing objects with == — checks reference, not value. Override equals() (or use record).
  • Forgetting to newPoint p; is a null reference, not a Point.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…