iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Access Modifiers

Java modifiers: public / private / protected / package-private, static, final, abstract, synchronized, volatile. The keywords that shape access + behaviour.

Java — modifiers

EXAMPLE
// ===== Access modifiers =====
public class User { ... }            // accessible everywhere
class Helper { ... }                 // package-private (default; same package only)

public class Foo {
    public int a;        // anywhere
    protected int b;     // subclasses + same package
    int c;               // package-private (default)
    private int d;       // this class only
}

// Best practice: most fields private; expose via methods.

// ===== static =====
// Belongs to the CLASS, not an instance.
public class MathUtil {
    public static final double PI = 3.14159;
    public static int add(int a, int b) { return a + b; }
}
MathUtil.add(2, 3);

// Static fields are shared across all instances (also across threads — beware races).

// ===== final =====
// On classes:    cannot be subclassed
public final class Money { ... }
// On methods:    cannot be overridden
public final void critical() { ... }
// On fields:     assigned once
public final int id = 42;
// On parameters: cannot be reassigned in method body
public void demo(final String name) { ... }
// On locals:     same; aids readability

// ===== abstract =====
public abstract class Shape {
    public abstract double area();   // no body; subclass must implement
    public void describe() { System.out.println(area()); }
}
class Circle extends Shape {
    double r;
    public double area() { return Math.PI * r * r; }
}

// You CANNOT instantiate an abstract class. It must be subclassed.

// ===== synchronized =====
// Mutual exclusion via the intrinsic lock of an object.
public synchronized void increment() {
    count++;
}
// Same as: synchronized(this) { count++; }

// Static synchronized uses the Class object's lock.

// Prefer java.util.concurrent (Lock, ReentrantLock, AtomicInteger) for new code.

// ===== volatile =====
// Ensures visibility across threads (no caching) but NOT atomicity for compound ops.
private volatile boolean running = true;

// For atomic counters, use AtomicInteger / AtomicLong, not volatile int + ++.

// ===== transient =====
// Excluded from default Java serialisation.
public class Session implements Serializable {
    private String userId;
    private transient String temporaryToken;   // not serialised
}

// ===== native =====
// Method implemented in another language (C via JNI). Rare in app code.
public native int sumNative(int a, int b);

// ===== Modifier interactions =====
// public + abstract: an API contract; subclasses fill in
// final + private: redundant (private methods are inherently final)
// static + final: a compile-time constant pattern (Java's idea of const)
// protected + final: rare; a method whose implementation must not be overridden but is visible to subclasses for calling

// ===== sealed (Java 17+) =====
// Restrict who can extend / implement:
public sealed class Shape permits Circle, Square, Triangle { ... }
public final class Circle extends Shape { ... }
public non-sealed class Square extends Shape { ... }   // sub-subclasses allowed
public final class Triangle extends Shape { ... }

// ===== Patterns to internalise =====
// - private fields by default; public methods only when needed
// - final on locals + params to document intent
// - static final UPPER_SNAKE for constants (only legitimate UPPER_SNAKE use)
// - Avoid synchronized in new code; reach for java.util.concurrent

// ===== Pitfalls =====
// - public mutable fields -> consumers depend on internals
// - volatile int + ++ -> NOT atomic; race condition
// - Inheriting from a non-final class without knowing if it was designed for inheritance
// - synchronized methods that hold the lock during I/O -> bottleneck

Why it matters

Modifiers shape access and behaviour: access (public/private/protected/default), static for class-level, final for immutable bindings, abstract for contracts, synchronized + volatile for concurrency (use java.util.concurrent first). sealed locks down inheritance in Java 17+. Default to the most restrictive that still works.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
public    // anywhere
protected // package + subclasses
          // (default) package-private
private   // declaring class only
Try it Yourself »

Discussion

Loading…