Classes and Objects
|
This section documents the current Java release line, with Java 25 LTS as the reference point (no specific patch version is pinned), as published at the Java developer portal, the Java Tutorials, and the Java SE API specification — which are the references these pages are written and verified against. This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
A class is a template that bundles state (fields) with behaviour (methods) and the code that builds an instance (constructors). This page follows the dev.java "Classes and Objects" track and the Java Tutorials on declaring classes.
Fields, Methods, and Constructors
this refers to the object the current method or constructor is running on; use it to tell a field
apart from a parameter of the same name. A constructor has the class’s name and no return type. See
Providing Constructors for Your
Classes.
class Account {
private final String owner; // instance fields: one copy per object
private long balanceCents;
Account(String owner, long openingCents) {
this.owner = owner; // this.owner is the field; owner is the parameter
this.balanceCents = openingCents;
}
void deposit(long cents) {
balanceCents += cents; // 'this.' is optional when unambiguous
}
long balanceCents() {
return balanceCents;
}
}
var a = new Account("Ada", 10_000);
a.deposit(2_500);
System.out.println(a.balanceCents()); // 12500
Every class implicitly extends
java.lang.Object
and inherits toString, equals, hashCode, and getClass from it; overriding them correctly is
covered on Inheritance and Polymorphism.
Constructor chaining and the default constructor
One constructor may delegate to another in the same class with this(…), which must be its first
statement. If a class declares no constructor at all, the compiler supplies a public no-argument
default constructor; writing any constructor of your own removes that gift.
class Rectangle {
private final int width;
private final int height;
Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
Rectangle(int side) {
this(side, side); // delegates to Rectangle(int, int)
}
Rectangle() {
this(1); // -> this(1, 1)
}
}
Delegating to a superclass constructor uses super(…) instead — see
Inheritance and Polymorphism.
Objects, References, and null
new allocates an object on the heap and returns a reference to it. A variable of a class type
holds that reference, never the object itself; assigning the variable copies the reference, so two
variables can name one object.
var x = new Account("Bo", 500);
var y = x; // same object, two references
y.deposit(100);
System.out.println(x.balanceCents()); // 600 -- x and y observe one object
A reference that points to nothing is null. Using . through a null reference throws
NullPointerException;
since Java 15 (opt-in in Java 14) the message names the exact expression that was null and the operation
attempted on it, which usually pinpoints the bug without a debugger.
String name = null;
// int n = name.length(); // NullPointerException: Cannot invoke "String.length()"
// because "name" is null
int n = (name != null) ? name.length() : 0;
java.util.Objects.requireNonNull(name, "name"); // fail fast, with a clear message
Prefer Optional over null for "might be absent" return values, and
guard constructor arguments with
Objects.requireNonNull.
Garbage collection
Java has no free and no delete. The garbage collector reclaims an object automatically once it is
no longer reachable from any live reference. You influence this only by dropping references — letting
a local go out of scope, or clearing a long-lived field. finalize() is deprecated for removal;
release external resources with try-with-resources over
AutoCloseable,
covered on I/O and Files.
static Members and Initializer Blocks
A static member belongs to the class, not to any instance: one copy, shared by all. Use static
methods for behaviour that needs no instance state, and static final fields for constants (named in
UPPER_SNAKE_CASE). See
Understanding Class Members.
class Circle {
static final double TAU = 2 * Math.PI; // constant: one per class
private static int created = 0; // shared mutable counter
private final double radius;
Circle(double radius) {
this.radius = radius;
created++;
}
static int instancesCreated() { // no 'this' available in a static method
return created;
}
double circumference() {
return TAU * radius;
}
}
Initializer blocks run when the class or the object is being set up:
class Lookup {
static final java.util.Map<String, Integer> CODES;
private final long createdAt;
static { // static initializer: runs once, when the class loads
CODES = java.util.Map.of("OK", 200, "NOT_FOUND", 404);
}
{ // instance initializer: runs before every constructor body
createdAt = System.nanoTime();
}
Lookup() {
// createdAt is already assigned here
}
}
A static block runs once when the class is initialized; an instance block runs on every construction,
just after super(…) and before the constructor body. Most classes need neither — prefer field
initializers and constructor code — but a static block is handy for building an unmodifiable constant
that takes more than a single expression.
Access Modifiers at a Glance
modifier same class same package subclass, other package everywhere
public yes yes yes yes
protected yes yes yes no
(package-private) yes yes no no
private yes no no no
Omitting the modifier means package-private. The guiding principle is encapsulation: keep fields
private and expose only the methods that form the type’s contract, so invariants (such as "balance is
never negative") stay enforceable. Add accessors deliberately, not reflexively — when the data really
is the API, a record is a better fit
(Records and Sealed Classes). The full rules,
including protected access across packages and the module system, are on
Packages and Modules.
JVM Memory: Stacks and the Heap
Each thread has its own stack of frames; a frame holds one method call’s parameters and local
variables. A primitive local sits directly in the frame, but an object local holds only a reference
into the shared heap, where new puts the object. Loaded class metadata — the
Class object,
method bytecode, and static fields — lives in metaspace.
See Also
-
Inheritance and Polymorphism —
extends,super(…), and overriding built on these class basics. -
Records and Sealed Classes — the concise way to write a transparent immutable data class.
-
Methods and Parameters — parameter passing, overloading, and
thisin more depth. -
Packages and Modules — the full access-control and visibility rules.