Four pillars, interfaces vs abstract classes, sealed types and records, overriding rules, init order, equals/hashCode, immutability, SOLID, nested classes, enums, generics and access control.
Theory
Q1
What are the four pillars of OOP and how does Java realise each?
basic
Encapsulation, abstraction, inheritance and polymorphism. Java realises them through access modifiers, interfaces/abstract classes, extends/implements, and virtual method dispatch.
Encapsulation: private state plus controlled methods so invariants are enforced in one place.
Abstraction: expose what an object does, hide how (interfaces, abstract classes).
Inheritance: reuse and specialise via extends (single class inheritance only).
Polymorphism: compile-time (overloading) and runtime (overriding, decided by the object's actual class).
⚠ Follow-up traps
Are getters/setters on every field encapsulation? No. That only exposes the state; real encapsulation protects invariants and hides representation.
Is overloading true polymorphism? It is static (compile-time) dispatch; "subtype polymorphism" refers to overriding.
#pillars#fundamentals
Q2
Abstraction vs encapsulation: what is the actual difference?
basic
Abstraction is a design-level decision about what to show (the contract); encapsulation is the implementation mechanism of hiding state and enforcing invariants behind that contract.
A PaymentGateway interface is abstraction; its private HTTP client and retry state are encapsulation.
⚠ Follow-up traps
Can you have one without the other? Yes. A public-field class with an interface has abstraction but poor encapsulation.
#abstraction#encapsulation
Q3
When do you choose an abstract class over an interface?
basic
Use an interface to define a capability or contract that unrelated classes can implement; use an abstract class when subclasses share state, constructors or a partially implemented template.
Aspect
Abstract class
Interface
State
instance fields
only public static final constants
Constructors
yes
no
Inheritance
one
many
Method access
any
public (or private helpers)
⚠ Follow-up traps
Can an abstract class have no abstract methods? Yes; it just can't be instantiated.
Can an interface have a constructor? No.
#abstract-class#interface
Q4
What are default, static and private methods in interfaces?
intermediate
default (Java 8) gives an inheritable implementation so interfaces can evolve without breaking implementors; static (Java 8) holds utility methods called via the interface name; private (Java 9) holds shared code for default/static methods.
interface Validator<T> { boolean validate(T t); default Validator<T> and(Validator<T> o) { return x -> validate(x) && o.validate(x); } static <T> Validator<T> notNull() { return x -> x != null; } private void log(String m) { System.out.println(m); }}
⚠ Follow-up traps
Are static interface methods inherited by implementing classes? No; call them as Validator.notNull() only.
Can a default method override Object.equals? No, compile error; classes always win over interface defaults.
#interface#default-methods
Q5
How does Java resolve the diamond problem with default methods?
intermediate
Rules in order: a class method (own or inherited) wins over any interface default; a more specific interface wins over a less specific one; otherwise the class must override and may choose with A.super.m().
interface A { default String hi() { return "A"; } }interface B { default String hi() { return "B"; } }class C implements A, B { public String hi() { return A.super.hi() + B.super.hi(); }}
⚠ Follow-up traps
What if C doesn't override? Compile error: inherits unrelated defaults.
What if one is abstract in B and default in A? Still a conflict; C must override.
#diamond#default-methods
Q6
Why is multiple inheritance of classes not allowed in Java?
basic
To avoid ambiguity over inherited state and method implementations (the diamond problem) and to keep construction and layout simple. Multiple inheritance of type is allowed through interfaces; of behaviour through defaults with explicit conflict resolution.
⚠ Follow-up traps
Then why does Java allow multiple interface inheritance? Interfaces have no instance state, so no field ambiguity.
#inheritance
Q7
What are sealed classes and why were they introduced?
intermediate
sealed (final in Java 17) restricts which classes may extend or implement a type through permits. It gives a closed hierarchy that the compiler knows, enabling exhaustive switch without default.
Each permitted subtype must be final, sealed or non-sealed.
⚠ Follow-up traps
Must permitted subclasses be in the same file? No; same module, or same package if in the unnamed module. If in the same file, permits can be omitted.
What does non-sealed do? Reopens that branch to arbitrary subclasses.
#sealed#java17
Q8
What is a record and what does the compiler generate?
basic
A record is a transparent, shallowly immutable data carrier. The compiler generates a canonical constructor, private final fields, accessors (name(), not getName()), and equals, hashCode, toString.
record Money(long cents, String currency) { Money { // compact constructor if (cents < 0) throw new IllegalArgumentException(); }}
⚠ Follow-up traps
Can a record extend a class? No (it implicitly extends java.lang.Record), but it can implement interfaces.
Is a record deeply immutable? No. A List component can still be mutated unless defensively copied.
Can a record have instance fields beyond components? No; static fields are allowed.
#records#java16
Q9
Where are records a good fit in a backend, and where not?
intermediate
Good for DTOs, API request/response models, value objects, projections and map keys. Poor for JPA entities (need a no-arg constructor, mutable state, proxies) and for types with identity-based equality or lifecycle.
⚠ Follow-up traps
Can Jackson serialise records? Yes, since Jackson 2.12 and Spring Boot 2.5+/3.x.
Can Hibernate use records as @Embeddable? Yes in Hibernate 6.2+; not as @Entity.
#records#dto#design
Q10
Explain method overriding rules.
basic
Same name and parameter types; return type same or covariant; access not narrower; no broader checked exceptions; cannot override private, static or final methods. Use @Override so the compiler checks it.
⚠ Follow-up traps
Can an override throw a broader unchecked exception? Yes, unchecked exceptions are unrestricted.
Is static method redefinition overriding? No, it is method hiding.
#overriding
Q11
What is method hiding?
intermediate
A static method in a subclass with the same signature hides the parent's. Resolution is by the declared (compile-time) type, not the runtime object. Fields are also hidden, never overridden.
⚠ Follow-up traps
Parent p = new Child(); p.staticM() calls which?Parent.staticM().
Can an instance method hide a static one? No; compile error.
#static#overriding
Q12
How does overload resolution work?
intermediate
At compile time the compiler picks by the static argument types in three phases: exact/widening primitive and subtyping, then boxing/unboxing, then varargs. The most specific applicable method wins.
⚠ Follow-up traps
m(Object) vs m(String) with null?m(String) is chosen (most specific).
m(int...) vs m(long) called with m(5)?m(long); widening beats varargs.
#overloading
Q13
What is a covariant return type?
intermediate
An overriding method may return a subtype of the parent's return type. The compiler adds a synthetic bridge method with the original signature that delegates to the new one.
class Animal { Animal self() { return this; } }class Dog extends Animal { @Override Dog self() { return this; } }
⚠ Follow-up traps
Do primitives support covariance? No; int vs long return is a compile error.
Where do you see bridge methods?Comparable<T> implementations and generic overrides; they show up in stack traces and reflection.
#covariant#overriding
Q14
How does constructor chaining work?
basic
this(...) calls another constructor of the same class; super(...) calls a parent constructor. Either must be the first statement (before Java 22 preview relaxations), and if neither is written the compiler inserts super().
⚠ Follow-up traps
Can you use both this() and super() in one constructor? No; both must be first.
Parent has no no-arg constructor and child doesn't call super(...)? Compile error.
#constructors#chaining
Q15
What is the order of initialisation with inheritance?
intermediate
Class loading (first use): parent static init, then child static init. Per new: parent instance initialisers and field initialisers (textual order), parent constructor body, then child field initialisers and instance blocks, then child constructor body.
⚠ Follow-up traps
Do static blocks run on every new? No, once per class load.
Can the parent constructor see child field values? Only defaults (0/null), because child fields are not initialised yet.
#init-order#inheritance
Q16
State the equals/hashCode contract.
basic
equals must be reflexive, symmetric, transitive, consistent and x.equals(null) is false. If a.equals(b) then a.hashCode() == b.hashCode(). Unequal objects may share a hash code, but collisions hurt performance.
⚠ Follow-up traps
Override only equals? Breaks HashMap/HashSet lookups.
Can hashCode be constant? Legal but degrades hashing to O(n) (treeified bins help only for Comparable keys).
#equals#hashcode
Q17
Why is `equals` with `instanceof` vs `getClass()` a design decision?
advanced
getClass() comparison preserves symmetry across subclasses but violates Liskov (a subclass instance never equals a parent). instanceof allows substitutability but breaks symmetry or transitivity once subclasses add state. Safest: make the class final or use composition.
⚠ Follow-up traps
What does Hibernate imply here? Proxies are subclasses, so getClass() equality on entities breaks; use instanceof plus business key or id.
#equals#liskov
Q18
Is it safe to use mutable fields in `hashCode`?
intermediate
No. If a key's hash changes after insertion into a HashMap/HashSet, the entry sits in the wrong bucket and becomes unreachable via get/contains/remove.
⚠ Follow-up traps
Will the entry disappear from iteration? No, it still iterates; it just can't be found by key.
#hashcode#mutability
Q19
How do you create an immutable class?
basic
Make the class final (or constructors private), all fields private final, no setters, defensively copy mutable inputs in the constructor and outputs in getters, and don't leak this during construction.
public final class Order { private final List<String> items; public Order(List<String> items) { this.items = List.copyOf(items); } public List<String> items() { return items; }}
⚠ Follow-up traps
Is Collections.unmodifiableList(list) enough? No; it's a view, mutations of the original show through. Use List.copyOf.
Why final class? To stop a subclass from adding mutability.
#immutability
Q20
What are the benefits of immutability for backend systems?
intermediate
Thread safety without locks, safe sharing and caching, safe use as map keys, simpler reasoning and failure atomicity. Cost: object allocation per change; mitigate with builders or withX copies.
⚠ Follow-up traps
Are final fields safely published? Yes, the JMM guarantees visibility of final fields after constructor completion if this does not escape.
#immutability#concurrency
Q21
Composition vs inheritance: which to prefer and why?
intermediate
Prefer composition ("has-a") because inheritance couples a subclass to the parent's implementation (fragile base class) and exposes all inherited methods. Use inheritance only for true is-a relationships designed for extension.
⚠ Follow-up traps
Classic example of inheritance breaking?HashSet subclass overriding add and addAll to count items: addAll internally calls add, so counts double.
How do you avoid delegating boilerplate? Interfaces + delegates, or Lombok @Delegate, or IDE generation.
#composition#inheritance
Q22
Explain SOLID with backend examples.
intermediate
S: a UserService should not also send emails and render PDFs; split into collaborators.
O: add a new discount rule by adding a DiscountStrategy bean, not by editing an if chain.
L: a ReadOnlyRepository subclass that throws on save violates substitutability.
I: split a fat OrderOperations interface so a reporting client doesn't depend on cancel().
D: services depend on PaymentGateway interface, injected by Spring, not on StripeClient.
⚠ Follow-up traps
Is DIP the same as dependency injection? No. DIP is the principle (depend on abstractions); DI is one technique to supply them.
#solid#design
Q23
What is the Liskov Substitution Principle and how is it commonly violated?
intermediate
Subtypes must be usable wherever the parent is expected without breaking correctness. Violations: strengthening preconditions, weakening postconditions, throwing unexpected exceptions, or ignoring the contract (e.g. Square extends Rectangle with coupled setters).
⚠ Follow-up traps
Does Collections.unmodifiableList violate LSP? Arguably yes; List.add is optional per its contract, which makes the type's contract weak.
#solid#lsp
Q24
Name the types of nested classes and their differences.
basic
Static nested (no outer instance), inner (non-static; holds an implicit outer reference), local (declared in a method), anonymous (unnamed, declared inline). Local and anonymous classes capture effectively final variables.
⚠ Follow-up traps
How do you instantiate an inner class from outside?outer.new Inner().
Which of these can have static members? Since Java 16, inner classes can declare static members too.
#inner-class#nested
Q25
Why can inner classes cause memory leaks?
intermediate
A non-static inner or anonymous class holds a hidden reference to its enclosing instance. If the inner object outlives the outer (stored in a cache, listener list, or thread), the outer and everything it references can't be collected. Prefer static nested classes or lambdas that don't capture this.
⚠ Follow-up traps
Do lambdas capture this? Only if they reference instance members.
#inner-class#memory
Q26
Anonymous class vs lambda: how do they differ?
intermediate
An anonymous class is a new class (own .class file) with its own this, can implement any interface or extend a class, and can have state. A lambda needs a functional interface, this refers to the enclosing instance, and it compiles via invokedynamic.
⚠ Follow-up traps
Can a lambda capture a non-final local? No; it must be effectively final.
Can an anonymous class implement two interfaces? No, only one supertype.
#lambda#anonymous-class
Q27
What can enums do in Java beyond constants?
basic
Enums are classes with a fixed set of singleton instances. They can have fields, constructors (implicitly private), methods, implement interfaces, and have constant-specific bodies. They provide values(), valueOf, ordinal(), name(), and work in switch, EnumMap, EnumSet.
Can an enum extend a class? No; it implicitly extends java.lang.Enum.
Is it safe to persist ordinal()? No; reordering constants corrupts data. Use EnumType.STRING or an explicit code.
#enum
Q28
Why is an enum the best way to implement a singleton?
intermediate
The JVM guarantees one instance per constant, thread-safe initialisation, and the serialisation and reflection attacks that break class-based singletons are blocked (Enum serialises by name; reflective newInstance throws).
⚠ Follow-up traps
Downside? Cannot extend a class and initialisation is eager at class load of the enum.
Which are final?getClass, notify, notifyAll, wait.
Default toString?ClassName@hex(hashCode).
#object
Q30
What is the default `equals` and `hashCode` in `Object`?
basic
equals is reference identity (this == o); hashCode is an implementation-specific identity hash, typically derived from the object header, not the memory address as such.
⚠ Follow-up traps
Is identity hashCode unique? No, collisions are possible.
#object#equals
Q31
Why is `clone()` considered broken and what are the alternatives?
intermediate
Object.clone() is protected, requires implementing the marker interface Cloneable, does a shallow field copy without calling constructors, and throws a checked CloneNotSupportedException. Prefer copy constructors, static factories or records with withX methods.
⚠ Follow-up traps
Shallow vs deep copy? Shallow copies reference fields as-is; deep recursively clones them, which you must implement.
Do arrays support clone? Yes, arr.clone() is public and shallow.
#clone
Q32
What happens if a class overrides `clone()` without implementing `Cloneable`?
intermediate
Calling super.clone() throws CloneNotSupportedException at runtime, because Object.clone checks for the Cloneable marker.
⚠ Follow-up traps
Does Cloneable declare clone()? No, it is an empty marker interface.
#clone#cloneable
Q33
What are generics and why were they added?
basic
Generics add compile-time type parameters to classes and methods, removing casts and catching type errors at compile time instead of ClassCastException at runtime.
⚠ Follow-up traps
Are generics a runtime feature? No; they are erased (see type erasure).
Can you use primitives as type arguments? No; use wrappers.
#generics
Q34
What is type erasure and what are its consequences?
intermediate
The compiler removes type arguments after checking, replacing type variables with their bound (or Object) and inserting casts. Hence List<String> and List<Integer> are the same class at runtime.
No new T(), new T[], instanceof List<String>, or generic static fields of type T.
Overloads differing only in type arguments clash (m(List<String>) vs m(List<Integer>)).
⚠ Follow-up traps
How do frameworks get generic types at runtime? Via Type tokens (TypeReference, ParameterizedTypeReference) using generic info retained in class signatures.
#generics#erasure
Q35
Explain wildcards: `?`, `? extends T`, `? super T` and PECS.
intermediate
Producer Extends, Consumer Super. List<? extends Number> can be read as Number but not added to (except null); List<? super Integer> can accept Integer but reads only yield Object.
static double sum(List<? extends Number> src) { double s = 0; for (Number n : src) s += n.doubleValue(); return s; }static void fill(List<? super Integer> dst) { dst.add(42); }
⚠ Follow-up traps
Is List<Integer> a List<Number>? No; generics are invariant. Arrays are covariant (and unsafe).
Why Collections.copy(List<? super T> dest, List<? extends T> src)? It is PECS in the JDK.
#generics#wildcards
Q36
Why are arrays covariant but generics invariant?
advanced
Arrays are reified and checked at runtime (ArrayStoreException), so covariance is allowed historically. Generics are erased, so covariance would allow heap pollution with no runtime check; invariance keeps compile-time safety.
⚠ Follow-up traps
What does Number[] a = new Integer[1]; a[0] = 1.5; do? Compiles, throws ArrayStoreException.
#generics#arrays
Q37
What is a bounded type parameter?
intermediate
<T extends Comparable<T>> restricts T so you can call bound methods. Multiple bounds use & with the class first: <T extends Number & Comparable<T>>.
⚠ Follow-up traps
Is extends used for interfaces in bounds? Yes, always extends, never implements.
#generics#bounds
Q38
What is heap pollution and `@SafeVarargs`?
advanced
Heap pollution is when a variable of a parameterised type refers to an object that isn't of that type, typically via raw types or generic varargs (T... creates a T[] that erases to Object[]). @SafeVarargs asserts the method doesn't misuse the array; it is allowed on static, final, private methods and constructors.
⚠ Follow-up traps
Why not on regular instance methods? They can be overridden by an unsafe version.
#generics#varargs
Q39
Explain Java access modifiers.
basic
Modifier
Class
Package
Subclass
World
private
yes
no
no
no
(default)
yes
yes
no
no
protected
yes
yes
yes
no
public
yes
yes
yes
yes
⚠ Follow-up traps
Can a top-level class be private or protected? No, only public or package-private.
Does protected allow access via a parent reference from a subclass in another package? No; only through the subclass type (or its subtypes).
#access-modifiers
Q40
How do Java modules (JPMS) affect `public`?
advanced
In a named module, a public type is accessible outside only if its package is exportsed (and reflectively only if opens). This enables strong encapsulation of internals, which is why --add-opens is needed for old frameworks on Java 17.
⚠ Follow-up traps
Why did Java 17 break reflection hacks? JDK internals are strongly encapsulated by default (JEP 403).
#access-modifiers#jpms
Q41
What does the `final` keyword mean on class, method and variable in OOP design?
basic
final class cannot be extended; final method cannot be overridden; final variable cannot be reassigned (a final reference can still point to a mutable object).
⚠ Follow-up traps
Can a final method be overloaded? Yes.
Can Spring proxy a final class? CGLIB proxies cannot subclass it, so @Transactional on final classes/methods silently has no effect or fails.
#final
Q42
What is the difference between `static` and instance members in OOP terms?
basic
Static members belong to the class (one copy, no this, no polymorphic dispatch); instance members belong to each object. Static methods can't be overridden or mocked easily, so heavy use hurts testability.
⚠ Follow-up traps
Can a static method access instance fields? Only through an object reference.
#static
Q43
What is the difference between `==` and `equals` for objects, and for enums?
basic
== compares references; equals compares logical equality as defined by the class. For enums == is correct and null-safe, as Enum.equals is final and identity-based.
⚠ Follow-up traps
Which is null-safe: a.equals(b) or Objects.equals(a, b)? The latter.
#equality#enum
Q44
What is the role of `toString()` and what pitfalls does it have in entities?
basic
toString gives a diagnostic representation used in logs and debuggers. In JPA entities, including lazy associations triggers extra queries or LazyInitializationException, and bidirectional relations cause infinite recursion. Also never include secrets.
⚠ Follow-up traps
Does Lombok @Data on an entity cause this? Yes, it generates toString, equals, hashCode over all fields.
#tostring#jpa
Q45
How do you design a good `compareTo` and keep it consistent with `equals`?
intermediate
compareTo must be antisymmetric, transitive and consistent; it is "consistent with equals" when compareTo == 0 iff equals is true. Inconsistency makes TreeSet treat distinct-by-equals items as duplicates.
⚠ Follow-up traps
Classic example?BigDecimal("1.0") and BigDecimal("1.00") are not equals but compareTo == 0, so a HashSet keeps both and a TreeSet keeps one.
Subtract ints for compare? Overflow risk; use Integer.compare.
#comparable#equals
Q46
What is the difference between `Comparable` and `Comparator`?
basic
Comparable defines a class's single natural order (compareTo); Comparator is an external, pluggable ordering (Comparator.comparing(...).thenComparing(...)), allowing multiple orders without modifying the class.
⚠ Follow-up traps
Null handling? Use Comparator.nullsFirst/nullsLast.
#comparable#comparator
Q47
What is the Template Method pattern and how does it relate to abstract classes?
intermediate
A final method in an abstract base defines the algorithm skeleton, calling abstract/hook methods that subclasses implement. Example: Spring's JdbcTemplate and AbstractRoutingDataSource; many are now callback/strategy based.
⚠ Follow-up traps
Why make the skeleton final? So subclasses can't change the algorithm order.
#patterns#abstract-class
Q48
Strategy vs State pattern: what's the difference?
intermediate
Both delegate to an interchangeable object. Strategy is chosen by the client and objects don't know each other (e.g. PricingStrategy). State is driven by the context's internal transitions and states usually trigger the next state (e.g. order lifecycle).
⚠ Follow-up traps
Can an enum act as either? Yes; enums with constant-specific methods are a compact strategy/state.
#patterns#design
Q49
What is dependency injection and how does it support OOP design?
basic
Objects receive collaborators from outside rather than constructing them, which supports DIP, loose coupling and test doubles. Prefer constructor injection: dependencies are explicit, can be final, and the object is never half-built.
⚠ Follow-up traps
Why not field injection? Hides dependencies, blocks final, needs reflection or the container for tests.
#di#solid
Q50
What is the difference between `instanceof` pattern matching and casting (Java 16+)?
intermediate
if (o instanceof Circle c) tests and binds in one step, removing a manual cast. Binding scope is flow-sensitive. With sealed types and Java 21 pattern switch it replaces visitor-like code.
double area(Shape s) { return switch (s) { case Circle c -> Math.PI * c.r() * c.r(); case Square q -> q.side() * q.side(); };}
⚠ Follow-up traps
Does this switch need default? Not if Shape is sealed and covers all permitted subtypes.
Is null handled?switch throws NPE on null unless there's case null.
#pattern-matching#java17
Q51
What is a marker interface and are annotations better?
basic
An interface with no methods (Serializable, Cloneable, RandomAccess) that tags a type; it can be used as a parameter type for compile-time checking. Annotations carry metadata and parameters but are not part of the type system.
⚠ Follow-up traps
When is a marker interface better? When you need to constrain method parameters to tagged types.
#marker#interface
Q52
How do the `abstract` keyword restrictions interact with other modifiers?
intermediate
abstract cannot combine with final, private, or static on a method (nothing could implement or dispatch it); a class with an abstract method must be declared abstract. A constructor can't be abstract.
⚠ Follow-up traps
Can an abstract class be final? No.
Can you call an abstract method from an abstract class constructor? Yes, but it runs on an uninitialised subclass, which is a classic bug.
#abstract#modifiers
Scenarios
Q53
What does this print?
intermediate
C.init x=0x=5
The parent constructor calls the overridden init before C's field initialisers run, so x is still 0. Never call overridable methods from constructors.
⚠ Follow-up traps
What if x were final int x = 5? A compile-time constant is inlined, so C.init x=5 prints; this is a subtle exception.
What if x is Integer? It would be null.
#init-order#constructors
Q54
What is the full output order?
intermediate
A-sB-sA-iA-cB-iB-cA-iA-cB-iB-c
Static blocks run once at class initialisation (parent first); instance blocks and constructors run per object, parent first.
⚠ Follow-up traps
Does B.class literal trigger static init? No; loading without initialisation.
Does accessing a static final constant trigger it? Not for compile-time constants.
#init-order#static
Q55
What gets printed with overloading and `null`?
intermediate
Compile error: reference to m is ambiguous, since String and Integer are both more specific than Object and neither is more specific than the other. Removing one overload makes the call resolve to the remaining specific one.
⚠ Follow-up traps
How to disambiguate? Cast: m((String) null).
#overloading#null
Q56
Overloading vs overriding in one call: what is printed?
intermediate
A.Object. B.f(String) is an overload, not an override. The compiler picks f(Object) from A's methods (static type), and the runtime finds no override of it in B.
⚠ Follow-up traps
What would catch this?@Override on B.f(String) gives a compile error.
And with B b = new B(); b.f("x")?B.String.
#overloading#overriding
Q57
What happens with field hiding?
intermediate
P P C. Fields are resolved by the static type, never polymorphically. get() is defined in P, so it sees P.name.
⚠ Follow-up traps
How many name fields does the object contain? Two.
#fields#hiding
Q58
What does a static method call through a null reference do?
basic
Prints hi. The compiler resolves a static method by the declared type and ignores the reference value, so no NPE. It is poor style and flagged by linters.
⚠ Follow-up traps
And for an instance method on null?NullPointerException.
#static#null
Q59
What happens if you override `equals` but not `hashCode` and use the class as a HashMap key?
basic
Almost always null. The two equal keys use identity hash codes, so they land in different buckets and equals is never consulted. It may print a by rare collision, which makes the bug intermittent.
⚠ Follow-up traps
Fix? Override hashCode with Objects.hash(id) (or use a record).
Does HashSet behave the same? Yes, it's backed by HashMap.
#equals#hashcode#hashmap
Q60
What happens when a mutable key is changed after insertion?
intermediate
false 1. The element is stored in the bucket for hash 1; contains looks in the bucket for hash 2. The element is lost to lookups and can't be removed (a memory leak in long-lived sets).
⚠ Follow-up traps
Does s.add(k) now add a second copy? Yes, size becomes 2 and k appears twice.
#hashset#mutability
Q61
Does this equals implementation satisfy the contract?
advanced
No. point.equals(colorPoint) is true but colorPoint.equals(point) is false, breaking symmetry. It also ignores y in Point, possibly a bug. Fixes: make the classes final, use composition (ColorPoint has a Point), or use getClass() in both (losing LSP).
⚠ Follow-up traps
Can you add state in a subclass and keep equals correct? Not with inheritance; Bloch's classic result.
#equals#symmetry
Q62
What is the output and why?
basic
false true true. new String creates a separate heap object; intern() returns the pooled instance, which is the literal a.
⚠ Follow-up traps
Why is String immutable? Enables pooling, caching of hash, thread safety and safe use in security-sensitive fields.
#equals#string
Q63
Can a subclass reduce a method's visibility?
basic
Compile error: attempting to assign weaker access privileges. An override must be the same or more visible, otherwise P p = new C(); p.run() would violate the parent contract.
⚠ Follow-up traps
Can it widen protected to public? Yes.
#overriding#access-modifiers
Q64
What happens with checked exceptions in overrides?
intermediate
Compile error. An override may throw the same, narrower or no checked exceptions, never broader. Unchecked exceptions are always allowed.
⚠ Follow-up traps
Can the override throw FileNotFoundException? Yes, it is a subclass of IOException.
Constructor rule? A subclass constructor must declare the parent constructor's checked exceptions.
#overriding#exceptions
Q65
What is printed for a private method "override"?
intermediate
P. Private methods are not inherited and so can't be overridden; C.who is an unrelated method. call() binds to P.who at compile time.
⚠ Follow-up traps
If who were package-private in P and C in a different package? Also not overridden; @Override would fail.
#overriding#private
Q66
A service class marked `final` is annotated with `@Transactional`. What happens?
intermediate
Spring's class-based (CGLIB) proxy cannot subclass a final class or override final methods, so Spring Boot either fails at startup (final class) or the transaction advice is silently skipped for final methods (calls run the target directly). Use interface-based proxies or remove final. Kotlin's default-final classes need the allopen plugin for the same reason.
⚠ Follow-up traps
Does it work with a private @Transactional method? No, proxies only intercept public/protected-visible external calls.
#final#proxies#spring
Q67
What happens in this self-invocation?
intermediate
No transaction starts for audit() when called from place(). The call goes through this, bypassing the Spring proxy. Move audit to another bean, or inject self, or use TransactionTemplate.
⚠ Follow-up traps
Does AspectJ weaving fix it? Yes; weaving changes bytecode so internal calls are advised.
#proxies#spring#encapsulation
Q68
A parent class constructor must call `super(...)` with a value computed from constructor args. How?
basic
Compute inline in the super(...) call, using a static helper: Child(int n) { super(format(n)); } with private static String format(int n). Instance methods can't be called before super returns.
⚠ Follow-up traps
Can you use a local variable computed before super? Not in Java 17/21; the first statement must be the explicit constructor call (Java 22 previews relaxing it).
#constructors#chaining
Q69
What does this record code do?
basic
Throws IllegalArgumentException from the compact canonical constructor. Compact constructors run validation/normalisation before fields are assigned automatically at the end; assigning to this.lo inside is an error, assign to the parameter instead.
⚠ Follow-up traps
Can you reassign parameter lo in the compact constructor? Yes, e.g. lo = Math.max(lo, 0); and the result is stored.
#records#validation
Q70
A record holds a `List<String>`. Is it immutable?
intermediate
Prints [a, b]. Records are only shallowly immutable. Fix with a compact constructor: members = List.copyOf(members);.
⚠ Follow-up traps
Does List.copyOf accept nulls? No, it throws NPE for null list or elements.
#records#immutability
Q71
Does a record break when you add an extra field?
intermediate
Instance fields outside the header are not allowed: compile error. Add a derived method instead, or a static factory. If you need extra mutable state, use a class.
record Person(String first, String last) { String full() { return first + " " + last; }}
⚠ Follow-up traps
Can a record define equals itself? Yes, but it must preserve the contract; rarely needed.
#records#limitations
Q72
What happens if you add a new subclass to a sealed hierarchy used in a switch?
advanced
Every exhaustive switch without default stops compiling until Triangle is handled, which is the point: the compiler finds all places affected. If code is compiled separately and not rebuilt, the runtime throws MatchException (IncompatibleClassChangeError in older preview forms).
⚠ Follow-up traps
Downside of default in a switch over sealed types? It silences the exhaustiveness check.
#sealed#switch
Q73
Can this class extend the sealed interface?
intermediate
No: compile error, because Updated isn't listed in permits. Add it to the list or declare it nested/in the same file without permits.
⚠ Follow-up traps
Can a record be a permitted subtype? Yes, records are implicitly final.
Can an enum? Yes, enums are implicitly final or sealed.
#sealed#compile-error
Q74
Design: how would you model payment methods so adding a new type is safe?
intermediate
Use a sealed interface with record implementations and pattern-matching switch for operations that vary by type; this makes the type set closed and compiler-checked. If new types come from plug-ins, use an open interface with Strategy beans instead. Trade-off: sealed favours adding operations, open interfaces favour adding types.
⚠ Follow-up traps
Which is the expression problem side for visitor? Visitor makes adding operations easy and types hard; sealed + switch gives the same with less boilerplate.
#sealed#design#polymorphism
Q75
What happens when two interfaces provide the same default method and the class is silent?
intermediate
Compile error: C inherits unrelated defaults for go(). Override go() in C and delegate with A.super.go() if desired.
⚠ Follow-up traps
What if A extends B and overrides go()? No conflict; A's more specific default wins.
#default-methods#diamond
Q76
A class and an interface both define `toString`-like method `name()`: who wins?
intermediate
base. The "class wins" rule: a method inherited from a superclass beats an interface default.
⚠ Follow-up traps
What if Base.name were package-private and not accessible? Compile error due to weaker access when implementing the interface.
#default-methods#resolution
Q77
What does this covariant override print?
basic
B. Dispatch is on the runtime type; the static type A only determines which signature compiles. Through bridge method A make() the call lands in B.make().
⚠ Follow-up traps
Can a.make() be assigned to B without a cast? No; static return type is A.
#covariant#polymorphism
Q78
What happens in the following generic code?
intermediate
Compiles with unchecked warnings; raw.add(42) succeeds due to erasure, and strs.get(0) throws ClassCastException at the compiler-inserted cast, far from the real bug (heap pollution).
⚠ Follow-up traps
How to defend? Avoid raw types; Collections.checkedList adds runtime checks.
#generics#erasure
Q79
Will this compile?
intermediate
Line 1 fails (invariance). Line 2 compiles. Line 3 fails: the compiler can't know the exact element type, so only null can be added. Use ? super Integer for writing.
⚠ Follow-up traps
What is "capture conversion"? The compiler treats ? as an unknown but specific type CAP#1.
#generics#wildcards
Q80
Why does this not compile and how do you fix it?
intermediate
T is erased, so the JVM can't instantiate it. Pass a Supplier<T> or Class<T> token: Box(Supplier<T> s) then s.get().
⚠ Follow-up traps
Why can't you create new T[10]? Same reason; use (T[]) new Object[10] with a warning, or Array.newInstance.
#generics#erasure
Q81
Do these two overloads compile?
intermediate
Compile error: name clash, same erasure save(List). Rename them or differentiate by another parameter.
⚠ Follow-up traps
Would different return types fix it? No; the return type isn't part of the signature.
#generics#erasure#overloading
Q82
What happens when you modify a `HashMap` key set via a subclass equals that uses `getClass()`, with a Hibernate proxy?
advanced
entity.equals(proxy) returns false because the proxy's class is a generated subclass, so entities may appear missing from Sets or fail contains. Use instanceof (or Hibernate.getClass) and compare a business key or non-null id; keep hashCode stable (for example a constant class hash or business key) across persist.
⚠ Follow-up traps
Why not use generated id in hashCode? It changes from null to a value on persist, moving the entity between buckets.
#equals#hibernate#proxies
Q83
A class has a `public` getter returning an internal `Date`. What can go wrong?
basic
Date is mutable, so callers can do getCreated().setTime(0) and corrupt the object's state. Return a copy or use immutable Instant/LocalDateTime from java.time.
⚠ Follow-up traps
Same problem with arrays and collections? Yes; return clones/unmodifiable copies.
#encapsulation#immutability
Q84
What happens when an immutable class leaks `this` in its constructor?
advanced
Another thread may receive the half-constructed object and read v as 0. The JMM's final-field guarantee requires that this not escape before the constructor ends. Use a static factory that registers after construction.
⚠ Follow-up traps
Is the same true when registering an inner class created in the constructor? Yes, it holds an implicit this.
#immutability#jmm#this-escape
Q85
What does the unmodifiable wrapper actually protect?
intermediate
[a, b] [a]. The wrapper is a read-only view of the live list; copyOf is a true immutable snapshot.
⚠ Follow-up traps
Does view.add("c") work? It throws UnsupportedOperationException.
Does List.of allow nulls? No, NPE.
#immutability#collections
Q86
What does shallow clone do here?
intermediate
Delhi. The clone shares the same Addr instance. Fix by cloning addr in clone(), or use a copy constructor.
⚠ Follow-up traps
Does super.clone() call the constructor? No, which is why final-field and invariant logic can be bypassed.
#clone#shallow-copy
Q87
What happens when a class extends a class with a clone-unfriendly final field?
advanced
A final mutable field copied by super.clone() can't be reassigned in clone() to deep-copy it (outside reflection), so cloneable designs conflict with final. This is another reason to prefer copy constructors or factories.
⚠ Follow-up traps
Alternative?record with a withX method, or a builder toBuilder().
#clone#final
Q88
Design: you have `class Stack extends ArrayList`. Why is this risky?
intermediate
It exposes add(index, e), remove, and get which break stack semantics, and ties the API to ArrayList forever. Use composition: a Stack class with a private Deque<E> and only push, pop, peek. (This is the very mistake made in java.util.Stack extends Vector.)
⚠ Follow-up traps
What should you use in production for a stack?ArrayDeque, not java.util.Stack.
#composition#inheritance#encapsulation
Q89
Counting wrapper over `HashSet` gives wrong results. Why?
intermediate
6, not 3. HashSet.addAll (from AbstractCollection) calls add for each element, so each is counted twice. Fix with composition and a forwarding class.
⚠ Follow-up traps
If you drop the addAll override? It works today, but silently breaks if the JDK changes the implementation: fragile base class.
#inheritance#fragile-base-class
Q90
Which SOLID principle does this violate, and how do you refactor?
intermediate
Open/Closed: every new customer type edits this method. Refactor to a PricingStrategy interface with one implementation per type, or put a discount() on the enum, and select by map lookup. Trade-off: more classes; for 3 stable types an enum with a method is enough.
⚠ Follow-up traps
Is every if chain an OCP violation? No; only when the set of cases changes often.
#solid#ocp#strategy
Q91
A `ReportService` fetches data, formats CSV, and emails it. What's the issue and fix?
basic
Single Responsibility: three reasons to change (data query, format, delivery). Split into ReportRepository, CsvFormatter, Mailer, and keep ReportService as orchestration. Each part can be unit-tested and replaced independently.
⚠ Follow-up traps
Can SRP be over-applied? Yes; one class per method makes code hard to follow. A "reason to change" is about actors, not methods.
#solid#srp
Q92
An interface `Repository` has `save`, `delete`, `findAll`, `export`. A read-only client implements it. What's wrong?
intermediate
Interface Segregation: the client is forced to implement save/delete (throwing UnsupportedOperationException), which also violates LSP. Split into ReadRepository and WriteRepository and compose them where both are needed (Spring Data does this with Repository, CrudRepository and ListCrudRepository).
⚠ Follow-up traps
Can default methods hide ISP problems? Yes, they make fat interfaces cheap to implement but don't fix coupling.
#solid#isp
Q93
A high-level `CheckoutService` does `new StripeClient()`. How do you apply DIP?
basic
Define PaymentGateway in the domain, make StripeGateway implements PaymentGateway, and inject via constructor. Tests then use a fake; switching providers touches only configuration.
Two implementations on the classpath? Spring fails with NoUniqueBeanDefinitionException unless @Primary or @Qualifier is used.
#solid#dip#spring
Q94
Does `Square extends Rectangle` with coupled setters pass this test?
intermediate
No. For a Square, setHeight(5) also changes width, so area is 25. The subtype changes behaviour callers rely on (postconditions). Model both as immutable shapes implementing a Shape interface with area().
⚠ Follow-up traps
Does immutability resolve it? Largely, since there are no setters whose contract differs.
#lsp#solid
Q95
What does this inner class code print and what is the leak?
intermediate
7. Inner keeps a hidden Outer.this, so the Outer instance stays reachable while i lives. Declare Inner as static and pass what it needs if the lifetimes differ.
⚠ Follow-up traps
How do you see the hidden field?this$0 in the decompiled/javap -p output.
#inner-class#memory
Q96
What does this local-variable capture produce?
basic
Compile error: local variables referenced from a lambda (or local/anonymous class) must be final or effectively final. Use AtomicInteger, or a one-element array only if single-threaded and justified.
⚠ Follow-up traps
Why this rule? Captured values are copied; mutation would diverge between copies and, across threads, raise visibility problems.
Can lambdas modify instance fields? Yes.
#lambda#local-class
Q97
What does `this` refer to inside an anonymous class vs a lambda?
intermediate
a.run() prints anon, l.run() prints outer. In a lambda this is the enclosing instance; in an anonymous class it is the anonymous instance.
⚠ Follow-up traps
How to reach outer from the anonymous class?T.this.n.
#anonymous-class#lambda
Q98
What happens when you call `ordinal()` for persistence, then reorder the enum?
intermediate
Existing rows keep integers (1) that now map to different constants: silent data corruption (PAID rows become SHIPPED). Use @Enumerated(EnumType.STRING) or an AttributeConverter with stable codes, and never reorder or delete constants for ORDINAL mappings.
⚠ Follow-up traps
Downside of STRING? Renaming a constant breaks old rows; also uses more space.
Hibernate 6 enum default? Still ORDINAL unless specified (6.x also supports native enum columns on some DBs).
#enum#jpa
Q99
What does this enum print?
advanced
5 class Op$2 class Op. Constants with bodies are anonymous subclasses, so getClass() differs from getDeclaringClass(); use the latter for EnumMap-style logic.
⚠ Follow-up traps
Why does Op.MUL.getClass() == Op.class fail? Because of the anonymous subclass.
#enum#class-bodies
Q100
Can you extend an enum or create an instance with `new`?
basic
No to both. Constructors are implicitly private and the enum is implicitly final (or sealed when a constant has a body). Reflection Constructor.newInstance throws IllegalArgumentException: Cannot reflectively create enum objects.
⚠ Follow-up traps
How do you add behaviour to an enum from outside? Make it implement an interface or use a Map<EnumType, Handler>.
#enum#compile-error
Q101
What are the results of calling `Enum.valueOf` with bad input?
basic
Throws IllegalArgumentException: No enum constant Status.paid; it is case-sensitive, and null yields NPE. For user input, write a lookup with Optional or a static map.
⚠ Follow-up traps
Does it trim whitespace? No.
#enum#exceptions
Q102
What does `toString()` on this object print, and how is the hash chosen?
basic
Something like Plain@1b6d3586: class name, @, and hex hashCode(). Never parse or rely on the value; it differs between runs.
⚠ Follow-up traps
Does hashCode() equal the memory address? Not guaranteed; HotSpot generates and stores an identity hash in the header lazily.
#object#tostring
Q103
Which collection behaves wrongly with this `compareTo`?
intermediate
1. TreeSet uses compareTo, not equals, so versions 1.0 and 1.5 are duplicates. Compare all significant fields: Comparator.comparingInt((Ver v) -> v.major).thenComparingInt(v -> v.minor).
⚠ Follow-up traps
What does a HashSet do with the same class? Depends on hashCode/equals, giving size 2.
#comparable#treeset
Q104
What does a constructor's call to an abstract method hazard look like in template classes?
advanced
NullPointerException: register() runs from the Handler constructor before Mail's field initialiser has created sinks. Do registration in an explicit init() after construction or via a factory.
⚠ Follow-up traps
Would a final field help? No; blank finals are still unassigned at that point and sinks is null when read.
#init-order#abstract-class
Q105
What does an interface constant "override" print?
basic
The assignment is a compile error: interface fields are implicitly public static final. Using the constant interface anti-pattern pollutes implementors' namespace; place constants in a final utility class or an enum.
⚠ Follow-up traps
Can Impl define its own LIMIT? Yes, it hides the interface field.
#interface#constants
Q106
A method takes `protected` access across packages. Does this compile?
advanced
other.touch() fails to compile; s.touch() and touch() work. Outside the package, protected access is only allowed through a reference of the subclass type (or its subtypes), not through a parent-typed reference.
⚠ Follow-up traps
Would it compile if Sub were in package a? Yes, protected includes package access.
#access-modifiers#protected
Q107
Interface evolution: you add a new abstract method to a published interface. What breaks and how do you avoid it?
intermediate
All implementors in other codebases stop compiling and fail at runtime with AbstractMethodError when binary-compatible code calls it. Add it as a default method with a safe implementation (how Collection.removeIf, List.sort and Map.getOrDefault were added in Java 8). Trade-off: defaults can't use instance state, so choose a sensible behaviour.
⚠ Follow-up traps
Can a default method break existing implementors? Yes, if a class already has a method with the same name but a weaker access or an incompatible return type.
#interface#default-methods#compatibility
Q108
What happens at runtime in this pattern-matching switch when a new record implements the sealed interface but the caller isn't recompiled?
advanced
The old bytecode's exhaustive switch has no branch for the new subtype, so it throws MatchException at runtime (Java 21; earlier previews threw IncompatibleClassChangeError). Rebuild dependents when you change a sealed hierarchy, or keep a defensive default at module boundaries.
⚠ Follow-up traps
Does an enum switch behave similarly? Switch expressions over enums throw MatchException/IncompatibleClassChangeError for an unknown constant when no default exists.
#sealed#switch#compatibility
Q109
Compare `Optional` returned from an overridden method versus `null`. What does a covariant `Optional<Dog>` do?
advanced
Compile error: Optional<Dog> is not a subtype of Optional<Animal> due to invariance, so it's not a valid covariant return. Declare the parent as Optional<? extends Animal> and the child as Optional<Dog>.
⚠ Follow-up traps
Does Optional<? extends Animal> hurt callers? They can read Animal from it; they never need to add to it.
#covariant#generics
Q110
A generic method signature `<T extends Comparable<T>> T max(List<T> l)` is called with `List<java.sql.Timestamp>`. What happens?
advanced
Compile error: Timestamp implements Comparable<java.util.Date>, not Comparable<Timestamp>, so T fails the bound. The fix is <T extends Comparable<? super T>>, the idiom used by Collections.max.
⚠ Follow-up traps
What does ? super T allow?T can inherit its Comparable from a superclass.