Classes & Objects
BeginnerDefine classes, create objects, write constructors, apply access modifiers, and understand how the this keyword and object lifecycle work.
Overview
A class is a blueprint; an object is an instance of that blueprint created at runtime on the heap. Classes define state (fields) and behaviour (methods). Constructors are special methods called at object creation — if you don't write one, the compiler adds a no-arg default. Access modifiers (public, private, protected, package-private) control visibility and are the foundation of encapsulation. The this keyword refers to the current object and is used to disambiguate field names and chain constructors.
Class Definition & Constructors
A constructor has the same name as the class and no return type. If you define any constructor, the compiler stops generating the default no-arg one. Constructor overloading (multiple constructors with different parameters) is common. Constructor chaining with this() calls another constructor in the same class — this() must be the first statement.
Java initialises fields before the constructor body runs. Instance initialisers (blocks without a name) also run before the constructor body.
public class BankAccount {
// Fields (state)
private String owner;
private double balance;
private static int totalAccounts = 0; // shared across all instances
// No-arg constructor
public BankAccount() {
this("Unknown", 0.0); // delegates to 2-arg constructor
}
// Parameterised constructor
public BankAccount(String owner, double initialBalance) {
if (initialBalance < 0) throw new IllegalArgumentException("Balance cannot be negative");
this.owner = owner; // 'this' disambiguates field from param
this.balance = initialBalance;
totalAccounts++;
}
// Copy constructor
public BankAccount(BankAccount other) {
this(other.owner, other.balance);
}
public void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("Amount must be positive");
balance += amount;
}
public boolean withdraw(double amount) {
if (amount > balance) return false;
balance -= amount;
return true;
}
// Getters
public String getOwner() { return owner; }
public double getBalance() { return balance; }
public static int getTotalAccounts() { return totalAccounts; }
@Override
public String toString() {
return "BankAccount[owner=" + owner + ", balance=" + balance + "]";
}
public static void main(String[] args) {
BankAccount acc1 = new BankAccount("Alice", 1000.0);
BankAccount acc2 = new BankAccount("Bob", 500.0);
BankAccount acc3 = new BankAccount(acc1); // copy constructor
acc1.deposit(200);
acc1.withdraw(50);
System.out.println(acc1); // BankAccount[owner=Alice, balance=1150.0]
System.out.println(BankAccount.getTotalAccounts()); // 3
}
}Access Modifiers
Java has four access levels, from most to least restrictive:
private — accessible only within the same class package-private (default, no keyword) — accessible within the same package protected — package-private + accessible in subclasses (even in other packages) public — accessible from anywhere
The golden rule of encapsulation: make fields private, expose behaviour through public methods. This lets you change the internal representation without breaking callers.
package com.example;
public class Person {
private String name; // only this class
int age; // package-private
protected String country; // this package + subclasses
public String id; // everywhere (avoid for mutable fields)
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getter — controlled read access
public String getName() { return name; }
// Setter — can add validation
public void setName(String name) {
if (name == null || name.isBlank())
throw new IllegalArgumentException("Name cannot be blank");
this.name = name;
}
@Override
public String toString() { return name + " (age " + age + ")"; }
}Object Lifecycle & toString / equals
Objects are created with new, which allocates memory on the heap and calls the constructor. Objects become eligible for garbage collection when no live references point to them — you don't need to free memory manually.
Every class implicitly extends Object, which provides default implementations of toString() (prints class name + hashCode in hex), equals() (reference equality), and hashCode(). Override these in your own classes for meaningful behaviour.
import java.util.Objects;
public class Point {
private final int x;
private final int y;
public Point(int x, int y) { this.x = x; this.y = y; }
// Override equals — value-based equality
@Override
public boolean equals(Object o) {
if (this == o) return true; // same reference
if (!(o instanceof Point p)) return false; // null or wrong type
return x == p.x && y == p.y;
}
// Override hashCode — must be consistent with equals
@Override
public int hashCode() {
return Objects.hash(x, y); // use Objects.hash for simplicity
}
// Override toString — readable representation
@Override
public String toString() { return "Point(" + x + ", " + y + ")"; }
public static void main(String[] args) {
Point p1 = new Point(3, 4);
Point p2 = new Point(3, 4);
Point p3 = p1;
System.out.println(p1 == p2); // false — different objects
System.out.println(p1.equals(p2)); // true — same values
System.out.println(p1 == p3); // true — same reference
System.out.println(p1); // Point(3, 4)
}
}Interactive Visualization
Key Points to Remember
- If you define any constructor, the compiler no longer generates a default no-arg constructor
- this() to chain constructors must be the first statement in the constructor body
- Make fields private; expose state through public getters and validated setters
- All classes extend Object implicitly — override toString(), equals(), hashCode() for proper behaviour
- equals() and hashCode() must be overridden together — inconsistency breaks HashMap/HashSet
- Objects become eligible for GC when all references to them go out of scope
Practice Classes & Objects in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the difference between a class and an object?
What happens if you don't define a constructor in a Java class?
What is constructor chaining? How is it achieved?
Why should you override hashCode() whenever you override equals()?
What are the four access modifiers in Java? When would you use each?
Ask Aria about Classes & Objects
Your personal AI tutor — ask anything about this concept