static fields, methods and blocks, whether static blocks can throw, why static methods can't be overridden or use instance members, and every use of final — including its real impact on thread safety and performance.
Published September 25, 2026
static and final look simple, but interviewers use them to test your understanding of class loading, compile-time binding and the memory model. Keep each answer crisp, and add one line of code.
static keyword mean?Short answer: static marks a member as belonging to the class rather than to any object. There's one copy, shared by all instances, and it's accessible without creating an object: Math.max(a, b), Integer.MAX_VALUE.
Key points to cover:
class Ticket {
private static int issued = 0; // one counter shared by all tickets
private final int number;
Ticket() { number = ++issued; } // not thread-safe: use AtomicInteger if tickets are created concurrently
static int issuedCount() { return issued; }
}
Learn it in depth → Classes and Objects
Short answer: A static { … } block runs once, when the class is initialised (on first use), before any object is created or any static method runs. It's used for complex static initialisation.
class CountryCodes {
static final Map<String, String> BY_ISO;
static {
Map<String, String> m = new HashMap<>();
m.put("IN", "India");
m.put("US", "United States");
BY_ISO = Collections.unmodifiableMap(m);
}
}
Key points to cover:
static final Map<String, String> BY_ISO = Map.of("IN", "India", …); is cleaner.Short answer: It can't throw a checked exception. There's nowhere to declare a throws clause, so checked exceptions must be caught inside the block. An unchecked exception thrown there is wrapped in an ExceptionInInitializerError, and the class becomes unusable: later attempts to use it fail with NoClassDefFoundError.
static {
try {
CONFIG = loadConfig(); // throws IOException
} catch (IOException e) {
throw new IllegalStateException("cannot load config", e); // becomes ExceptionInInitializerError
}
}
Common trap: saying the exception can be "declared with a throws clause in the class". Classes have no throws clause. This is a common error in prepared answer sheets.
Short answer: No. Overriding relies on runtime dispatch on the object's type, and static methods are bound at compile time to the class. A subclass static method with the same signature hides the parent's method.
class Parent { static String id() { return "parent"; } }
class Child extends Parent { static String id() { return "child"; } } // hiding, not overriding
Parent p = new Child();
System.out.println(p.id()); // "parent": decided by the reference type (and a compiler warning)
Short answer: Not directly. A static method has no this, because no particular object is involved, so it can't refer to instance fields or methods. It needs an object reference to reach them.
class Counter {
int value;
static void reset(Counter c) {
// value = 0; // compile error: non-static field referenced from a static context
c.value = 0; // fine: goes through an instance
}
}
Key points to cover:
final keyword do?Short answer: It means "can't be changed", in three places:
String, Integer, LocalDate).final int maxRetries = 3; // maxRetries = 4; → compile error
class Base { final void audit() { } } // subclasses can't override audit()
final class Money { } // class X extends Money → compile error
Key points to cover:
final fields must be assigned exactly once: at their declaration, in an initialiser block, or in every constructor. This is called a "blank final".static final field with a primitive or String value set from a compile-time constant is a constant. The compiler inlines it into the code that uses it.final variables?Short answer:
static final int MAX_SIZE = 100;.@Service
class OrderService {
private final OrderRepository repository; // injected once, never reassigned
OrderService(OrderRepository repository) { this.repository = repository; }
}
final contribute to immutability and thread safety?Short answer: final fields can't be reassigned, and the Java Memory Model gives them a special guarantee. Once a constructor finishes, any thread that sees the object also sees the final fields' fully initialised values, without synchronisation (provided this didn't escape during construction).
Key points to cover:
final doesn't make the referenced object immutable. A final List can still have items added to it. Combine final with immutable types, or with defensive copies.Learn it in depth → Volatile and the Java Memory Model
final?Short answer: Very few. The JIT compiler is already good at inlining non-final methods (it tracks which classes are actually loaded and deoptimises if that changes), so marking methods final rarely makes code faster. Use final for design and correctness, not speed.
Key points to cover:
final does matter:
static final compile-time constants are inlined into calling code. Changing one requires recompiling the classes that use it, which is a classic stale-constant bug.final fields get memory-model visibility guarantees.static final fields can be constant-folded by the JIT.final improve performance by reducing method-call overhead?Short answer: In early JVMs, somewhat. On modern HotSpot, not meaningfully. The JIT uses class hierarchy analysis to inline methods that have only one loaded implementation, whether or not they're final, and it inlines polymorphic call sites that are hot. Don't claim final as a performance optimisation. Say it communicates intent and prevents incorrect overriding.
Q: What is "effectively final"?
A: A local variable that is never reassigned after initialisation, even without the final keyword. Lambdas and anonymous classes can capture it. The rule exists because captured variables are copied, so allowing changes would create confusing, inconsistent state.
Q: Can a constructor be static or final?
A: No. Constructors initialise instances, so static makes no sense. They aren't inherited, so final has nothing to prevent.
Q: Can an abstract method be final or static?
A: No. An abstract method must be overridden, while final forbids overriding and static methods can't be overridden. Both combinations are compile errors.
Q: What's the difference between final, finally and finalize?
A: final is a modifier (no reassignment, no overriding, no subclassing). finally is the block that always runs after try/catch. finalize() is the deprecated GC cleanup hook on Object.
Q: When does a class's static initialisation run? A: On its first active use: creating an instance, calling a static method, or reading or writing a non-constant static field. Merely declaring a variable of that type, or accessing a compile-time constant, doesn't trigger it.