A class declares a new reference type and how its objects behave. This page covers ordinary classes (JLS chapter 8); enum classes and record classes, which are special kinds of class, have their own pages.
Class declarations
NormalClassDeclaration:
{ClassModifier} class TypeIdentifier [TypeParameters]
[extends ClassType] [implements InterfaceTypeList] [permits TypeName {, TypeName}]
ClassBody
ClassBody:
{ {ClassBodyDeclaration} }
ClassBodyDeclaration:
FieldDeclaration | MethodDeclaration | ClassDeclaration | InterfaceDeclaration | ;
InstanceInitializer | StaticInitializer | ConstructorDeclaration
public abstract sealed class Account permits Savings, Current {
private static int nextId = 1; // class variable
protected final int id; // instance variable, blank final
private long balance;
protected Account(long opening) { // constructor
this.id = nextId++;
this.balance = opening;
}
public long balance() { return balance; }
public abstract double rate(); // no body: subclasses provide it
public void deposit(long amount) {
if (amount <= 0) throw new IllegalArgumentException("amount");
balance += amount;
}
}
final class Savings extends Account {
Savings(long opening) { super(opening); }
@Override public double rate() { return 0.03; }
}
non-sealed class Current extends Account {
Current() { super(0); }
@Override public double rate() { return 0; }
}
Class modifiers
| Modifier | Meaning | Allowed on |
|---|---|---|
public | Accessible everywhere (subject to module exports) | Top-level and member classes |
protected, private | Access, as for other members | Member classes only |
abstract | Cannot be instantiated; may declare abstract methods | Any class except enum and record |
static | Has no enclosing instance | Member classes only (local enums, records and interfaces are implicitly static) |
final | Cannot be subclassed | Any class except enum (implicit on records) |
sealed | Only the permitted classes may extend it directly (Java 17) | Any class except local and anonymous |
non-sealed | A subclass of a sealed class that is open again to any subclass (Java 17) | Direct subclasses of a sealed class or interface |
strictfp | Obsolete since Java 17, when all floating-point became strict | Any class |
A class may not be both abstract and final, and may have
at most one of final, sealed and
non-sealed. The same modifier twice, or two access modifiers, is an
error.
Superclass and superinterfaces
extendsnames one direct superclass. Without it the superclass isObject. A class cannot extend a final class, itself (directly or through a cycle),EnumorRecord.implementslists any number of interfaces. A class that is not abstract must implement every abstract method it inherits.- Java has single inheritance of classes and multiple inheritance of interfaces: state and constructors come from one chain of superclasses, behaviour may also come from default methods.
Sealed classes
A sealed class (Java 17, JEP 409) lists the classes that may extend it
directly. Each permitted subclass must itself be final,
sealed or non-sealed (records and enums are implicitly
final or sealed). The rules (JLS 8.1.1.2, 8.1.6):
- In a named module, every permitted subclass must be in the same module; in the unnamed module, in the same package.
- Every class named in
permitsmust directly extend the sealed class. - If
permitsis left out, the permitted subclasses are the classes in the same compilation unit that extend it; there must be at least one. permitswithoutsealed, ornon-sealedon a class with no sealed direct supertype, is an error.
Sealing lets the compiler know every subtype, which makes
switches over them exhaustive
without a default.
Members
The members of a class are its fields, methods and member classes and interfaces, whether declared or inherited from the superclass and superinterfaces (JLS 8.2). Constructors, initialisers and private members of the superclass are not inherited. Members with package access are inherited only by subclasses in the same package.
Fields
FieldDeclaration:
{FieldModifier} UnannType VariableDeclaratorList ;
FieldModifier:
Annotation public protected private static final transient volatile
| Modifier | Meaning |
|---|---|
static | One variable for the class, not one per object |
final | Assigned exactly once: in its initialiser, or in every constructor or an initialiser |
transient | Not part of the object’s persistent state; skipped by Java serialisation |
volatile | Every read sees the latest write by any thread; see Threads and the memory model |
A field may not be both final and volatile. One
declaration may declare several fields, int x, y = 1, z[];, where
z is an int[]. Static fields are initialised when the class
is initialised, instance fields when each object is created, in textual order with
the initialisers (see Execution).
Methods
MethodDeclaration:
{MethodModifier} MethodHeader MethodBody
MethodHeader:
Result MethodDeclarator [Throws]
TypeParameters {Annotation} Result MethodDeclarator [Throws]
MethodDeclarator:
Identifier ( [ReceiverParameter ,] [FormalParameterList] ) [Dims]
MethodBody:
Block | ;
| Modifier | Meaning |
|---|---|
public, protected, private | Access |
abstract | No body (;); the class must be abstract, and subclasses implement it |
static | A class method: no this, called on the class |
final | Cannot be overridden or hidden |
synchronized | Holds the object’s monitor (the class’s, if static) while it runs |
native | Implemented outside Java, for example in C through JNI; no body |
strictfp | Obsolete since Java 17 |
abstract cannot be combined with private,
static, final, native,
synchronized or strictfp. The signature of a
method is its name and its parameter types after erasure; a class may not declare two
methods with the same signature, or whose signatures erase to the same one. The
return type and throws clause are not part of the signature.
- Parameters may be
final. The last parameter may be variable arity (Java 5), writtenType... name; inside the method it is an array, and callers may pass a list of values, an array, or nothing. - A receiver parameter (Java 8) is an optional first parameter
named
this, only there to carry type annotations on the object the method is called on:void m(@ReadOnly Point this). - A method with a non-
voidresult must not be able to complete normally: every path ends inreturnwith a value or in a throw. - The old form
int f()[], with brackets after the parameter list, still means a method returningint[].
static int sum(int... values) {
int total = 0;
for (int v : values) total += v;
return total;
}
sum(); // 0
sum(1, 2, 3); // 6
sum(new int[] {4, 5}); // 9
static <T extends Comparable<T>> T max(T a, T b) { // a generic method
return a.compareTo(b) >= 0 ? a : b;
}
Overriding and overloading
An instance method overrides a method of a superclass or superinterface when it has the same name and a subsignature of it, and the overridden method is accessible (JLS 8.4.8). The overriding method:
- must not have weaker access (
publiccannot becomeprotected); - must have a return type that is the same, or a subtype for reference types
(covariant return, Java 5); for
voidand primitive types it must be the same; - may not declare checked exceptions beyond those the overridden method declares, though it may declare fewer or narrower ones;
- may not override a
finalmethod, and may not be static.
The @Override annotation asks the compiler to check that the method
really overrides or implements something. Inside the overriding method,
super.name(…) calls the overridden version. Private methods and static
methods are not overridden.
Overloading is declaring several methods with the same name and different parameter types. The compiler chooses among them at compile time from the static types of the arguments; see Contexts and overload resolution.
Constructors
ConstructorDeclaration:
{ConstructorModifier} [TypeParameters] SimpleTypeName ( [ReceiverParameter ,] [FormalParameterList] ) [Throws]
ConstructorBody
ConstructorBody:
{ [BlockStatements] ExplicitConstructorInvocation [BlockStatements] }
{ [BlockStatements] }
ExplicitConstructorInvocation:
[TypeArguments] this ( [ArgumentList] ) ;
[TypeArguments] super ( [ArgumentList] ) ;
ExpressionName . [TypeArguments] super ( [ArgumentList] ) ;
Primary . [TypeArguments] super ( [ArgumentList] ) ;
- A constructor has the name of its class and no return type. Its only modifiers are the access modifiers; it is never inherited.
- A class with no constructor gets a default constructor with no
parameters, the same access as the class, that calls
super(). - A constructor may call another constructor of the same class with
this(…)or a superclass constructor withsuper(…), at most once. If it calls neither, it starts with an implicitsuper(). Calls that would form a cycle are an error. - A private constructor stops other classes creating instances; it is used for singletons, factories and classes of static utilities.
- A constructor may only use
return;without a value.
Flexible constructor bodies (Java 25)
Before Java 25 the call to this(…) or super(…) had to be
the first statement. Since Java 25 (JEP 513) statements may come before it. They
are the prologue; the statements after are the epilogue. The
prologue and the arguments of the call are an early construction context
(JLS 8.8.7), where the object does not exist yet as far as the code is concerned:
| Allowed in the prologue | Not allowed |
|---|---|
|
Local variables and local classes Calls to static methods, and any code that does not use the current object Throwing exceptions, for fail-fast checks A simple assignment to a field of this class that has no initialiser: x = 1;Using the enclosing instance of an inner class: Outer.this.f
|
this as a value, as in print(this)Reading any field, even one already assigned Calling instance methods, with or without this.super.f or super.m()Creating an instance of an inner class of this class return
|
class PositiveRange extends Range {
private final String label;
PositiveRange(int low, int high, String name) {
if (low < 0) throw new IllegalArgumentException("negative"); // checked first
label = name; // allowed: a field of this class, no initialiser
super(low, high); // the superclass constructor runs after the check
}
}
super(…) means a superclass constructor that calls an overridden method sees them already setInitialisers
class Config {
static final Map<String, String> DEFAULTS;
static { // static initialiser: runs once, when the class is initialised
DEFAULTS = new HashMap<>();
DEFAULTS.put("mode", "fast");
}
final List<String> log = new ArrayList<>();
{ // instance initialiser: runs for every new object
log.add("created");
}
}
- A static initialiser (
static { … }) runs once, when the class is initialised, together with the static field initialisers in textual order. It may notreturnor throw checked exceptions. - An instance initialiser (
{ … }, Java 1.1) runs for every new object, after the superclass constructor returns and before the rest of the constructor, together with the instance field initialisers in textual order. It may throw a checked exception only if every constructor declares it (or, in an anonymous class, always).
Nested classes
A class declared inside another class, interface or block is nested (Java 1.1). Nested classes that are not static are inner classes, which have an enclosing instance.
| Kind | Declared | Enclosing instance | Can use |
|---|---|---|---|
| Static nested class | As a member, with static | None | The enclosing class’s static members, including private ones |
| Inner member class | As a member, without static | An instance of the enclosing class | All members of the enclosing instance |
| Local class | In a block | The enclosing method’s this, if not in a static context | Also the block’s effectively final local variables |
| Anonymous class | In an expression: new T(…) { … } | As for a local class | As for a local class |
- Member classes of interfaces, and member enums, records and interfaces, are implicitly static. Local enums, records and interfaces (Java 16) are implicitly static too, so they cannot use the block’s local variables.
- Since Java 16 inner classes may declare static members and static initialisers; before, only constant variables could be static.
- The enclosing instance is written
Outer.this. From outside, an inner class instance is created with a qualified expression:outer.new Inner(). - An anonymous class has no name and no constructor; it passes its arguments to the
superclass constructor and uses an instance initialiser instead. Having no name, it
can never be extended. Since Java 9 the diamond can be used:
new Comparator<>() { … }.
class Outer {
private int count = 0;
class Counter { // inner member class
void inc() { count++; } // uses Outer.this.count
}
static class Pair { // static nested class
final int a, b;
Pair(int a, int b) { this.a = a; this.b = b; }
}
Runnable task(String name) {
class Task implements Runnable { // local class
public void run() { System.out.println(name + " " + count); }
}
return new Task();
}
Comparator<String> byLength() {
return new Comparator<>() { // anonymous class
public int compare(String x, String y) { return Integer.compare(x.length(), y.length()); }
};
}
}
Outer o = new Outer();
Outer.Counter c = o.new Counter();
Outer.Pair p = new Outer.Pair(1, 2);