Java interview bank

Questions interviewers actually ask, each answered at the length you would say it aloud, with the topic to reread if you were not sure.

64 questions Junior Senior
All levels Junior Mid Senior
Reveal one by one Show all answers
Report an error

Language core

21 questions
01 How do primitive and reference types differ in Java? Junior common reveal ▾ hide ▴

A primitive variable holds one of Java’s built-in Boolean, integral, or floating-point values and cannot hold null. A reference variable holds a reference to an object or array, or the null reference. Assigning a primitive copies its value. Assigning a reference copies the reference, so both variables can identify the same mutable object. Arrays are reference types even when their elements are primitive. Generic type arguments must be reference types, which is why a list of integers uses List and introduces boxing.

read more Data types
Was this clear?
02 What can go wrong in Java widening, narrowing, and numeric promotion? Mid common reveal ▾ hide ▴

Widening to a wider integral type preserves the value, but widening int or long to floating point can lose precision. Narrowing integral conversions discard high bits, while floating-to-integral conversion rounds toward zero and has defined results for NaN and out-of-range values rather than throwing. Numeric promotion means byte, short, and char arithmetic usually runs as int. Intermediate expressions therefore matter: assigning an int multiplication to long does not prevent earlier overflow. Widen before the operation or use the Math exact methods when overflow must be rejected.

read more Data types
Was this clear?
03 Why are boxing, wrapper equality, and null a dangerous combination? Mid common reveal ▾ hide ▴

Autoboxing converts a primitive to its wrapper and unboxing extracts the primitive. The conversions are often implicit in collections, arithmetic, comparisons, conditional expressions, and method calls. Unboxing null throws NullPointerException. Using == between wrapper references tests identity, and the required cache for certain small boxed constants can make that bug pass small-value tests. Use primitives when absence is impossible, validate nullable wrappers before arithmetic, and compare nullable wrapper values with Objects.equals. Also inspect overload selection because boxing, unboxing, and primitive widening affect which method is called.

read more Data types
Was this clear?
06 How does Java select a catch clause and continue execution after an exception? Mid common reveal ▾ hide ▴

The JVM tests handlers around the throw site in source order and selects the first whose parameter can receive the exception object’s runtime type. If none matches, the current frame completes abruptly and the search continues in its caller. A subtype handler must precede its supertype or the later branch is unreachable. After a handler completes normally, execution continues after the entire try statement, not after the failed instruction. Rethrowing the same object preserves its identity and original trace; translating it should create a domain exception with the original as its cause.

read more Exceptions
Was this clear?
09 How do scope and definite assignment differ for a Java local variable? Junior common reveal ▾ hide ▴

Scope says where a declared name can be referenced in source code. Definite assignment asks a separate control-flow question: has every path reaching this read already assigned the local? A variable can be in scope yet still be illegal to read. Fields and new array elements receive default values, but local variables do not. If one branch does not assign the local, that path must assign it later or leave before the read with return or throw. A final local adds the requirement that it be definitely unassigned before assignment.

Was this clear?
14 Are Java records immutable, and what contract does a compact canonical constructor provide? Mid common reveal ▾ hide ▴

A record fixes its component fields as private and final and derives accessors plus value-oriented object methods, but that guarantee is shallow. A List, array, date-like object, or other mutable component can still change after construction. I use the canonical constructor to reject invalid values and establish ownership, often with List.copyOf or an array copy. A compact canonical constructor lets me validate or rebind parameters before the compiler assigns them to fields. I also review accessors, because returning a mutable component can expose internal state even when its field is final.

Was this clear?
19 What correctness guarantees and boundaries matter in a Java 21 pattern switch over records and sealed types? Mid common reveal ▾ hide ▴

Record patterns test and deconstruct components, and a pattern switch selects the first applicable label. The compiler rejects a branch dominated by an earlier broader pattern and requires a switch expression to be exhaustive. For a sealed hierarchy I normally list every permitted branch and omit default so a newly added subtype fails at consumer recompilation. Null remains separate: case null handles it, otherwise the switch throws NullPointerException and default does not match it. Separate compilation still creates a binary-evolution boundary, so deployed old consumers need compatibility tests.

Was this clear?
21 What contract does a Java record header define? Junior common reveal ▾ hide ▴

A record header declares the complete component state of a transparent data carrier. For each component, the compiler provides a private final field and a public same-named accessor. It also derives the canonical constructor, equals, hashCode, and toString from the component list. The record class is implicitly final and directly extends java.lang.Record, though it can implement interfaces and add behavior. Component names, types, and order are public API because callers, reflection, construction, object methods, and record patterns all observe that shape.

read more Records
Was this clear?
25 What contract does a sealed Java type establish, and what must each permitted subtype declare? Junior common reveal ▾ hide ▴

A sealed class or interface names the types allowed to extend or implement it directly. The permits list does not enumerate every descendant and does not limit how many instances exist. Each ordinary direct subtype must choose final to end its branch, sealed to control another permitted set, or non-sealed to reopen inheritance. Records are implicitly final. I use sealing when one module owns a finite domain model and adding a root variant should force consumer review. It is a compile-time hierarchy constraint, not authentication, authorization, or a sandbox.

Was this clear?
29 How do immutability, equals, ==, and the string pool interact in Java? Junior common reveal ▾ hide ▴

A String never changes its code-unit sequence after construction, so transformations return a result and strings can safely keep stable hashes as map keys. equals compares content, while == compares whether two references identify the same object. The language interns equal literals and constant string expressions, which can make == appear to compare content in small tests. Runtime input and new String do not carry that assumption. I use equals or Objects.equals for value semantics and reserve == for deliberate identity checks. intern is a canonicalization tool, not a comparison method or default optimization.

read more Strings
Was this clear?
31 When should Java code use +, StringBuilder, or StringBuffer? Mid common reveal ▾ hide ▴

I use + for a short expression because it states the result clearly and the compiler may optimize its implementation. I use StringBuilder when a loop or conditional process appends an unknown number of pieces, keeping the builder local and returning one final String. String.join or Collectors.joining is clearer when the work is only delimiter-based joining. StringBuffer synchronizes individual methods, but that does not make a multi-call read-modify-write protocol atomic. I rarely share a text buffer across threads; separate local builders usually express ownership better. Performance claims still require measurement on the target JDK and workload.

read more Strings
Was this clear?
33 How do you design the target and retention of a custom Java annotation? Junior common reveal ▾ hide ▴

I start with the consumer and the phase where it reads metadata. A source or compiler tool may need SOURCE, a bytecode transformer may need CLASS, and reflection requires RUNTIME; CLASS is the default, so I never assume runtime visibility. I restrict Target to the exact declaration or type-use contexts the consumer scans, which lets javac reject meaningless placements. I also define what absence means, whether the annotation is public API, and tests that exercise the real consumer. Adding metadata without an active consumer does not add behavior.

read more Annotations
Was this clear?
37 When should a Java API use a named type parameter instead of a wildcard? Mid common reveal ▾ hide ▴

I use a named type parameter when the signature must preserve a relationship across two or more positions, such as an input element type and the return type, or a source and destination. I use a wildcard when one parameter has a constrained but otherwise irrelevant element type. List<?> is enough for observation, ? extends T describes a producer, and ? super T describes a consumer. A type parameter that appears only once often adds no useful relationship. Conversely, replacing every T with ? can erase information callers need. I validate the choice by listing the safe reads and writes for each parameter.

read more Generics
Was this clear?
41 What is the precise difference between a nested class and an inner class in Java? Junior common reveal ▾ hide ▴

Nested class is the umbrella term for a class declared inside another class or interface: it can be a member, local, or anonymous class. An inner class is a nested class that is not explicitly or implicitly static. A static member class is therefore nested but not inner. Member and local records and enums, plus member classes of interfaces, are implicitly static. A normal local class and an anonymous class are inner classes, although one declared in a static context can have no immediately enclosing instance. I name both the declaration form and static status when explaining the relationship.

read more Inner classes
Was this clear?
43 What does effectively final mean for a local variable captured by a local or anonymous class? Mid common reveal ▾ hide ▴

A captured local variable, parameter, or exception parameter must be final or effectively final. Effectively final means it omits the final modifier but obeys the assignment restrictions such that adding final would not introduce an error. The restriction applies to rebinding the variable, not to mutating the referenced object, so a captured List may receive add calls while the local name cannot later point to another list. I avoid one-element arrays used merely to bypass this rule. They hide shared mutable state; I put state and its invariants in a named owner and add synchronization only when the execution model requires it.

read more Inner classes
Was this clear?
46 How does Java resolve inherited default methods? Mid common reveal ▾ hide ▴

A concrete instance method from a class or superclass takes precedence over an interface default. Among interface candidates, a declaration from a more specific subinterface overrides one from its parent. If unrelated interfaces contribute override-equivalent defaults and neither wins, the implementing class must override the method. Its body can select a direct superinterface implementation with InterfaceName.super.method(), combine both, or provide new behavior. Static and private interface methods do not enter this process because implementations do not inherit them. I verify a difficult case by drawing the full type graph and compiling a minimal example.

read more Interfaces
Was this clear?
50 How do overloading, overriding, and dynamic dispatch interact in a Java method call? Mid common reveal ▾ hide ▴

The compiler first uses the receiver’s static type plus the argument types to choose an accessible method signature, which is where overload resolution happens. If that signature denotes an overridable instance method, runtime dispatch then selects the most specific override for the actual receiver object. Static, private, and final methods do not participate in ordinary overriding. Changing an argument variable to a wider static type can therefore select another overload without changing its runtime object. I add @Override to intended overrides and compile small ambiguous cases rather than reasoning from runtime types alone.

Was this clear?
52 How do object identity, value equality, and hashing differ in Java? Mid common reveal ▾ hide ▴

Reference == asks whether two references identify the same object, while equals expresses the value relation promised by a type. Object starts with identity-based equals, but value types often override it. Equal objects must return the same hash code, so equals and hashCode are designed and tested together. Fields used in both should stay stable while an object is a hash key; otherwise lookup can fail after mutation. In inheritance hierarchies, adding subtype-only equality state can break symmetry or transitivity, which is why immutable final classes or records are often safer value objects.

Was this clear?
53 How do `getMethod()` and `getDeclaredMethod()` differ, and how do you select an overload safely? Mid common reveal ▾ hide ▴

getMethod finds a public method in the type’s invocation view, including eligible inherited methods. getDeclaredMethod searches only the current class but can return any visibility. Neither performs source-level overload resolution: I must supply the exact declared parameter classes, so int differs from Integer and an implementation class does not match an interface parameter. I define whether the caller needs a public or declaration view, map external operation names to an allowlist of complete signatures, reject ambiguity, and test inherited, bridge, primitive, interface, varargs, and null cases.

read more Reflection
Was this clear?
57 What does Java type erasure remove, and what generic metadata can reflection still observe? Mid common reveal ▾ hide ▴

Erasure maps a type variable to its leftmost bound, or Object when it has no explicit bound, and maps a parameterized type to its raw class for JVM descriptors. That is why List and List objects share one runtime class. The compiler can still emit a Signature attribute for declared fields, methods, and supertypes. Generic reflection APIs parse that declaration metadata, but they do not recover a caller’s local type argument from an arbitrary object. I separate runtime class identity, executable descriptors, and declared generic signatures when diagnosing frameworks.

read more Type erasure
Was this clear?
62 What can you safely read and write through each Java wildcard form? Mid common reveal ▾ hide ▴

From List<?> I can read Object and add no non-null value. From List<? extends T> I can read T, but I still cannot add a non-null T because the captured element type may be narrower. Through List<? super T> I can add T and its subtypes, while a read is only guaranteed as Object because the actual element type may be a supertype. Null is type-correct for every reference element type, but that says nothing about the collection or business null policy. These references may still support clear, remove, or reordering, so extends is not an immutability guarantee.

Was this clear?

Numbers and text

1 question
04 How do you choose types for decimal money and Unicode text? Mid occasional reveal ▾ hide ▴

For money defined in decimal units, BigDecimal preserves decimal values and makes scale and rounding explicit. Construct it from decimal text or an exact integer, not from an already rounded double. Decide whether equality includes scale: equals distinguishes 1.0 from 1.00, while compareTo treats them as numerically equal. For text, char is one UTF-16 code unit, not every Unicode code point or displayed grapheme. Use String code-point APIs for supplementary characters, and use a text-boundary library when the requirement concerns user-perceived characters.

read more Data types
Was this clear?

Error handling

2 questions
05 How do checked and unchecked exceptions differ, and when would you define each kind? Junior common reveal ▾ hide ▴

Checked exception classes are the Throwable hierarchy outside RuntimeException and Error. The compiler requires a caller to catch or declare them. I use a checked domain exception when callers should be forced to choose propagation, translation, or recovery, such as failing to load required external data. I use an unchecked exception for a violated precondition, illegal object state, or programming defect. Neither category dictates that every caller catch the failure. The type describes the contract; the catch boundary should exist only where code can apply a meaningful policy.

read more Exceptions
Was this clear?
55 How should a reflection adapter classify and preserve invocation failures? Mid common reveal ▾ hide ▴

I separate lookup failure, denied access, incompatible receiver or arguments, and an exception thrown by target code. NoSuchMethodException, IllegalAccessException, and IllegalArgumentException identify the infrastructure stages. Method.invoke wraps a target exception in InvocationTargetException, so I inspect its cause and preserve it when translating to a stable domain exception or result. I do not return null for every failure because null may be a valid result. For proxies, I also check the interface throws clause because an undeclared checked exception can become UndeclaredThrowableException. Tests assert both the public classification and the original cause chain.

read more Reflection
Was this clear?

Resource management

1 question
07 What guarantees does try-with-resources provide when both work and cleanup fail? Mid common reveal ▾ hide ▴

Every successfully initialized, non-null resource receives a close attempt in reverse initialization order. A close failure does not prevent attempts to close the remaining resources. If the body already threw, that exception stays primary and later close failures are attached to it as suppressed exceptions. If the body succeeded, the first close failure becomes primary and later ones are suppressed onto it. I inspect getSuppressed as well as getCause during diagnosis. This differs from a cause: a cause explains why an exception was created, while suppression preserves concurrent cleanup failures.

read more Exceptions
Was this clear?

Failure boundaries

1 question
08 What should an exception policy do at service, task, or API boundaries? Senior occasional reveal ▾ hide ▴

A boundary should classify expected domain failures, unexpected defects, cancellation, and failures that are safe to retry. It can translate low-level exceptions into stable domain types while retaining the original cause, then record the complete exception once where the request or task outcome is owned. Public responses should be sanitized and correlated with internal diagnostics rather than exposing paths, SQL, or credentials. Retry only transient failures of suitably idempotent operations. InterruptedException normally propagates; if the signature cannot do that, cleanup should finish and the thread’s interrupt status should be restored.

read more Exceptions
Was this clear?

Expressions

1 question
10 What is the practical difference between && and & on Boolean operands? Junior common reveal ▾ hide ▴

Both can produce a Boolean conjunction, but && short-circuits: it evaluates the right operand only when the left operand is true. Boolean & always evaluates both operands. That difference controls side effects, exceptions, and safe guards such as value != null && value.isReady(). Java otherwise evaluates operands left to right. I use && for conditions and reserve & for deliberate non-short-circuit Boolean work or bitwise integer operations. Tests should make right-side execution visible, because identical truth tables can hide the behavioral difference.

Was this clear?

Control flow

3 questions
11 How does a modern Java switch expression differ from a traditional switch statement? Mid common reveal ▾ hide ▴

A switch expression produces a value and must cover every selector value. An arrow rule does not fall through; it can provide an expression, a block, or throw. A block rule uses yield to provide the result. Traditional colon-labeled statement groups can fall through until break, which remains useful for compatible older code but is easy to change incorrectly. For enums or sealed hierarchies, the compiler may prove completeness without a source default. I still test binary evolution and null behavior at the API boundary rather than treating exhaustiveness as all-purpose validation.

Was this clear?
12 How do you review a Java loop for correctness and termination? Mid common reveal ▾ hide ▴

I identify the initial state, the condition checked for each iteration, the update, and a measure that moves toward termination. For an array index, the usual invariant separates the processed half-open interval [0, index) from the unprocessed remainder, with index < length as the upper bound. I test empty and one-element inputs, the exact threshold, early break, and no-match behavior. I also inspect continue paths to ensure they do not skip a required update. Enhanced for is clearer when only element values are needed; explicit indexing is better when replacing slots.

Was this clear?
16 How do Java 17 switch expressions differ from pattern matching for instanceof and from pattern switches? Mid common reveal ▾ hide ▴

A Java 17 switch expression is a stable construct that exhaustively produces a value; arrow rules do not fall through, and a block rule uses yield. Pattern matching for instanceof is also stable and binds a typed variable only where flow proves the match succeeded. Combining type patterns with switch was preview work in Java 17, not part of its stable language. The final pattern-switch syntax arrived later, in Java 21, and later examples may also use when guards or record patterns. For a Java 17 contract, I use enum switches and instanceof chains and enforce the boundary with —release 17.

Was this clear?

Language evolution

2 questions
13 Which language features are available at the Java 17 source level, and which one actually became final in Java 17? Junior common reveal ▾ hide ▴

Stable Java 17 source can use switch expressions, text blocks, records, pattern matching for instanceof, and sealed classes. Their final releases were 14, 15, 16, 16, and 17 respectively, so only sealed classes became final in Java 17 itself. I keep that provenance separate from the project baseline because it prevents inaccurate minimum-version claims. I also compile with javac —release 17: running a newer JDK does not stop generated source from using Java 21 syntax such as final pattern switches or record patterns.

Was this clear?
17 Which major Java 21 application features are stable, and which release-note features must not be treated as stable Java 25 APIs? Junior common reveal ▾ hide ▴

Virtual threads, record patterns, pattern matching for switch, and sequenced collections are final Java 21 features and require no preview flag. Structured Concurrency and String Templates were previews in Java 21. Structured Concurrency continued through a fifth preview in Java 25 and its API changed, while the later String Templates proposal was withdrawn and the syntax is absent from Java 25. I enforce a stable Java 21 contract with javac —release 21 and no —enable-preview, rather than inferring stability from a release-note list.

Was this clear?

Type design

1 question
15 What does a sealed hierarchy guarantee in Java 17, and where does that guarantee stop? Mid common reveal ▾ hide ▴

A sealed class or interface controls its permitted direct subtypes. Each direct subtype must be final, sealed, or non-sealed, with records implicitly final. In a named module those subtypes must share the module; in an unnamed module they must share the package. The guarantee stops at a non-sealed branch, whose descendants are open again. That makes sealed types good for domain alternatives owned by one module, but usually wrong for cross-module plugin contracts. In stable Java 17 I consume the hierarchy with polymorphism or instanceof patterns, not a final type-pattern switch.

Was this clear?

Concurrency

1 question
18 Why should virtual threads usually be created per task, and how do you limit a scarce downstream resource? Mid common reveal ▾ hide ▴

A virtual thread is a cheap representation of a blocking task, so a thread-per-task executor avoids sizing and queueing a worker pool. It does not create database connections, remote quota, file descriptors, heap, or CPU capacity. I let each independent blocking task have a virtual thread, then gate only the scarce operation with a semaphore, connection pool, or rate limiter sized from the resource contract. CPU-bound work remains limited by processor parallelism. I also test interruption, timeouts, cancellation, and ThreadLocal memory at realistic concurrency.

Was this clear?

Collections

1 question
20 What contract does a Java 21 sequenced collection provide, and why is reversed() often misunderstood? Mid occasional reveal ▾ hide ▴

A sequenced collection has a defined encounter order and uniform first, last, and reverse-order operations. The concrete collection still decides which mutations it supports, so addFirst can throw on an unmodifiable or structurally constrained implementation. reversed() returns a backed view rather than a snapshot: changes to the original are visible through the view, and supported view mutations write through. I name it reverseView, document ownership, and copy explicitly when a caller needs an independent snapshot. Copying the container still does not deep-copy mutable elements.

Was this clear?

Object design

6 questions
22 How should a record canonical constructor establish invariants and ownership? Mid common reveal ▾ hide ▴

I use the canonical constructor as the one path that validates every component and takes ownership of mutable inputs. A compact constructor omits the parameter list, lets me validate or rebind implicit component parameters, and relies on compiler assignments after its body. I normalize values there rather than in accessors, preserving the copy invariant. Lists usually become List.copyOf results; arrays require explicit copies, often at both construction and access. An auxiliary constructor must delegate with this so it cannot bypass the canonical path. Element mutability still needs a separate policy.

read more Records
Was this clear?
23 Why are mutable and array components dangerous in record equality and hashing? Mid common reveal ▾ hide ▴

Derived equality and hashing use every component field. A mutable list or map can change after construction, changing the record hash and breaking lookup when the record is stored as a HashMap key. Final only fixes the field reference; it does not freeze the referenced object. Arrays add another trap because their inherited equals and hashCode are identity based, not content based. I prefer immutable value components, make defensive copies, and use an unmodifiable List for logical sequences. If an array is unavoidable, I design equals and hashCode together and test their contract.

read more Records
Was this clear?
42 How do you choose between a static nested class and a member inner class? Mid common reveal ▾ hide ▴

I ask whether every helper instance inherently belongs to one outer object and needs implicit access to that object’s state. If yes, a member inner class can express that ownership, and callers create it with outer.new Inner(). If the helper needs only explicit constructor data, I make it static. That removes the implicit enclosing-instance relationship and makes lifetime easier to see. Static does not prohibit access to private instance members through an explicit outer reference. I also inspect long-lived listeners, caches, and executor tasks, because an inner object stored there can keep its outer object graph reachable.

read more Inner classes
Was this clear?
45 When would you choose a Java interface over an abstract class? Junior common reveal ▾ hide ▴

I choose an interface when callers need a behavior contract that unrelated classes can implement, or when one class must expose several independent capabilities. I choose an abstract class when implementations share per-instance fields, constructor rules, protected helpers, or a common lifecycle. Default methods let an interface derive convenience behavior from existing operations, but they do not give it instance state. I start from the caller’s smallest useful contract and avoid creating an interface merely to mirror every public method of one class. Contract tests then run against each substitute implementation.

read more Interfaces
Was this clear?
49 What does encapsulation protect beyond making fields private? Junior common reveal ▾ hide ▴

Encapsulation assigns ownership of representation and state transitions to one object. I start by writing its invariants, then make construction establish them and ensure every public mutation preserves them. Private fields help, but unrestricted setters, returned mutable collections, and retained aliases can still bypass the boundary. I prefer operations such as withdraw or reschedule that express one valid domain transition. For arrays and collections, I define ownership and copy where required. I test invalid construction, every mutation boundary, and attempts to change state through input or output aliases.

Was this clear?
51 When should you replace inheritance with composition? Mid common reveal ▾ hide ▴

I use inheritance only when the subtype can preserve every caller-visible promise of the base type: accepted inputs, result meaning, exceptions, side effects, invariants, and lifecycle. Reusing implementation is not enough. If a candidate subtype must reject valid base inputs or reinterpret an operation, substitution is already broken. Composition is usually better when I need a replaceable policy, optional capability, or reusable helper because the dependency stays explicit and can vary independently. I validate the decision with one base-type contract test suite run against every implementation, not with a class diagram alone.

Was this clear?

Pattern matching

2 questions
24 What should you verify when using record patterns with a sealed hierarchy? Senior occasional reveal ▾ hide ▴

A record pattern checks the record type and invokes component accessors to feed nested patterns. Null matches no record pattern, so a pattern switch needs case null or an explicit non-null boundary. Branch order matters because an earlier broad pattern can dominate a later one. With a sealed hierarchy, listing every permitted subtype lets the compiler check exhaustiveness when the consumer is recompiled; a broad default can hide omissions. I also compile with the promised —release because record patterns became final in Java 21, and I test separately deployed binaries for hierarchy evolution.

read more Records
Was this clear?
26 How do sealed types improve switch exhaustiveness, and why can default be harmful? Mid common reveal ▾ hide ▴

For a switch over a sealed selector, the compiler calculates type coverage from the permitted direct subtypes. I normally list each closed branch and omit default, so adding a root variant makes consumers fail when recompiled and identifies the code that needs review. A non-sealed branch is covered by a pattern for that branch type, not by enumerating its current implementations. Null is separate: case null handles it; otherwise a null selector throws NullPointerException, and default does not catch it. Separate binaries still need compatibility tests because old consumers are not recompiled automatically.

Was this clear?

Modules and packaging

2 questions
27 What location and inference rules constrain permitted direct subtypes? Mid occasional reveal ▾ hide ▴

When a sealed root is in a named module, every directly permitted subtype must be in that same module, although packages may differ. In an unnamed module, those subtypes must share the root package. A permits entry names a direct subtype that is accessible to the root; grandchildren belong to their direct sealed parent instead. If permits is omitted, the compiler infers direct subtypes declared in the same compilation unit, not everything in the package. Moving one inferred subtype to another source file therefore requires adding an explicit permits clause. I test these rules with the production module path and —release.

Was this clear?
54 What determines whether Java reflection may access a non-public member in a named module? Senior common reveal ▾ hide ▴

Ordinary reflection starts with Java access rules and module readability and exports. Suppressing those checks also depends on the relationship between the caller module and the target package, especially whether that package is open to the caller. trySetAccessible reports failure as false, while setAccessible(true) throws InaccessibleObjectException when access cannot be enabled. I prefer a public API; when a framework genuinely needs deep reflection, the owning module declares a qualified opens contract. I test on the production module path without accidental global --add-opens flags and treat access failure as deployment configuration, not missing data.

read more Reflection
Was this clear?

API evolution

3 questions
28 How would you evolve a published sealed hierarchy safely? Senior occasional reveal ▾ hide ▴

Adding a permitted root subtype is source incompatible for exhaustive switches: recompiled consumers must add a branch. Already compiled consumers do not receive that check, and an enhanced switch with no applicable label can throw MatchException when old consumer code sees the new subtype. I test a new producer with both recompiled and still-deployed old consumers. I also inspect reflection, serialization, framework proxies, and protocol mappings because PermittedSubclasses metadata does not solve those compatibility concerns. If a compatibility window needs fallback behavior, I put it at a controlled version boundary rather than adding default everywhere.

Was this clear?
36 How do you evolve a published annotation interface safely? Senior occasional reveal ▾ hide ▴

I treat it as API used by source callers, processors, runtime readers, and existing class files. A new required element breaks old source when recompiled, so a new element normally needs a semantically safe default. Defaults are read from the current annotation interface rather than copied into each use, which preserves readability of old binaries but can still change behavior. Removing an element, changing its type, narrowing Target, or changing Retention needs compatibility analysis. I test old and new source, processors, and mixed binary versions, including access to every element rather than merely discovering the annotation.

read more Annotations
Was this clear?
48 How do you evolve a published Java interface safely? Senior occasional reveal ▾ hide ▴

I separate source, binary, and behavioral compatibility. A new abstract method breaks implementing source on recompilation; a new default can preserve many old binaries but still collide with another superinterface or change behavior. I cleanly rebuild all available implementations and callers, then run old implementation binaries with the new interface to exercise mixed deployment. Contract tests compare results, exceptions, side effects, null rules, and concurrency guarantees. I also inspect functional-interface status and compile-time constants, because a second abstract method breaks lambda targets and old caller binaries may retain an inlined constant value.

read more Interfaces
Was this clear?

Text and Unicode

1 question
30 What does String.length count, and how do you truncate Java text safely? Mid common reveal ▾ hide ▴

String.length counts UTF-16 code units, and charAt and substring use offsets in that same unit. A supplementary Unicode code point occupies a surrogate pair, so an in-range substring can still split it. For a code-point limit, I count with codePointCount and convert the chosen count to an endpoint with offsetByCodePoints. User-visible characters are a different contract because one grapheme cluster can contain several code points. UI truncation therefore needs a suitable Unicode text segmenter. I test BMP text, supplementary characters, combining marks, empty input, zero, and the exact limit.

read more Strings
Was this clear?

API boundaries

1 question
32 Which hidden contracts should you make explicit when Java strings cross system boundaries? Mid occasional reveal ▾ hide ▴

I specify the charset for every byte boundary, usually the protocol-defined UTF-8, and choose whether malformed input is rejected or replaced. I distinguish null, empty, and blank values rather than normalizing them accidentally. For machine keys I state locale and Unicode normalization rules; natural-language casing uses the content locale. I also check whether an API interprets literal text or regex syntax. split takes a regex and drops trailing empty fields by default, while replaceAll has separate replacement metacharacters. Boundary tests include non-ASCII text, trailing empties, regex characters, dollar signs, backslashes, and malformed bytes.

read more Strings
Was this clear?

Reflection

1 question
34 How do Java reflection queries differ for direct, inherited, and repeatable annotations? Mid common reveal ▾ hide ▴

Declared queries inspect metadata directly on the element. On classes, non-declared queries can also follow the superclass rule defined by Inherited, but that rule does not traverse interfaces or copy annotations onto overridden methods. Repeatable annotations add another distinction: singular getAnnotation can return null when multiple uses are stored in their container, while getAnnotationsByType unfolds the container. I choose the query from the framework contract rather than by habit, then test zero, one, and multiple uses plus superclass, interface, and override boundaries. Type-use metadata requires AnnotatedType APIs instead.

read more Annotations
Was this clear?

Compilation

3 questions
35 When should you use annotation processing instead of runtime reflection? Mid occasional reveal ▾ hide ▴

I use processing when a decision can be made from the compile-time language model and should produce a diagnostic, source, or resource before deployment. Processors work with Element and TypeMirror in rounds, so they can inspect source types that do not yet have loadable Class objects. Reflection fits behavior that must inspect RUNTIME metadata from loaded program elements. In Java 25, I configure processing explicitly with a processor path, module path, processor name, or proc option; placing a processor only on the ordinary class path is not enough to express that intent. Clean-build tests verify generated outputs.

read more Annotations
Was this clear?
58 Why can erasure reject one pair of methods yet cause the compiler to generate another method? Senior common reveal ▾ hide ▴

Two declarations such as read(List) and read(List) erase to the same signature, read(List), so they cannot coexist as overloads. A bridge solves a different problem: preserving overriding when a specialized implementation no longer has the erased parameter or return type expected by its generic supertype. The compiler emits an adapter marked bridge and usually synthetic, which casts or adapts before delegating. Reflection scanners may see both entries. I compare erased signatures first, then use Method.isBridge and the full signature rather than selecting a method by name or array order.

read more Type erasure
Was this clear?
64 What is wildcard capture, and what can a capture helper prove? Senior occasional reveal ▾ hide ▴

Capture conversion gives one wildcard expression a fresh internal type, often printed as CAP#1 in javac diagnostics. A private generic helper can name that type as T, which makes operations such as reading an element from one List<?> and writing it back to the same list type-safe. Capture does not erase the bound and does not inspect runtime elements. Two separate wildcard expressions normally receive separate captures, so a helper cannot justify moving a value between List and List merely because both parameters are List<? extends Number>. That relationship must appear in the public signature with a named T or directional PECS bounds.

Was this clear?

API design

2 questions
38 Why is `List<Integer>` not a subtype of `List<Number>`, and how does PECS help? Mid common reveal ▾ hide ▴

Java generic types are invariant. If List were assignable to List, code holding the Number view could add a Double and corrupt the original integer list. PECS recovers safe flexibility at a use site: a List<? extends Number> can produce values as Number but cannot accept a non-null Number, while a List<? super Integer> can consume Integer values but only produces Object safely. For a copy method I connect both sides with one T: the source is List<? extends T> and the destination is List<? super T>. If one parameter both reads and writes T, I normally use List.

read more Generics
Was this clear?
63 When should an API use a named type parameter instead of a wildcard? Mid common reveal ▾ hide ▴

I use a wildcard when one parameter has an element type that is constrained but irrelevant by name, such as List<?> for observation or Iterable<? extends T> for a source. I declare when the signature must preserve one relationship across multiple positions: source to destination, input to result, or a mutable list to its update function. A type parameter used only once often adds no information, while replacing every T with ? destroys useful relationships. I decide by writing the required read, write, and return capabilities first, then choosing the smallest signature that proves them without casts.

Was this clear?

Runtime model

1 question
39 What does type erasure remove, and which generic type information can reflection still see? Mid common reveal ▾ hide ▴

Erasure maps a type parameter to its leftmost bound, or usually Object, and parameterized instantiations share one runtime class. That is why an ordinary ArrayList object cannot pass an instanceof List test and why T.class and new T() are unavailable. The compiler inserts casts and may generate bridge methods to preserve source-level behavior. Class files can still carry generic signatures on declarations, so reflection may report a field declared as List through getGenericType. That metadata belongs to the declaration, not every list object. List<?> is reifiable because runtime checking only needs the raw List identity.

read more Generics
Was this clear?

Code review

1 question
40 How do you review an unchecked generic cast or `@SafeVarargs` claim? Senior occasional reveal ▾ hide ▴

I treat the warning as a proof obligation, not compiler noise. First I trace every value that can enter the object through raw aliases, reflective construction, deserialization, array covariance, or varargs. Then I state the invariant that makes the cast safe and keep both the cast and suppression in the smallest helper. For generic varargs, @SafeVarargs is valid only as a promise that the implementation does not expose the array or use it to create incompatible writes; the annotation does not verify that promise. I compile with -Xlint:all, test adversarial element types, and remove the suppression if no local argument proves safety.

read more Generics
Was this clear?

Callbacks

1 question
44 When is an anonymous class not equivalent to a lambda expression? Mid common reveal ▾ hide ▴

A lambda can target only a functional interface and does not create a new this scope; this inside it refers to the enclosing object. An anonymous class creates its own object and this, can extend an ordinary class, and may declare fields, instance initializers, and extra methods. Those differences matter when code uses identity, qualified this, overload resolution, or per-callback state. Before converting, I identify the target type and every use of this or extra members, then run the callback after registration rather than only at construction time. Concision alone is not evidence that behavior is preserved.

read more Inner classes
Was this clear?

Functional programming

1 question
47 What exactly makes an interface functional, and why use `@FunctionalInterface`? Mid common reveal ▾ hide ▴

A functional interface has an abstract method set that yields one function descriptor after Java applies override-equivalence, return-type substitutability, and the special handling of public Object methods. It may still declare default, static, and private methods because those do not create another abstract contract. A lambda or method reference uses the function descriptor as its target type. The annotation is not required for lambda conversion, but it asks the compiler to reject accidental changes, such as adding an unrelated second abstract method. I keep it on interfaces intentionally designed as callback or strategy targets.

read more Interfaces
Was this clear?

Runtime architecture

1 question
56 What contract must an `InvocationHandler` define for a JDK dynamic proxy? Senior occasional reveal ▾ hide ▴

The handler must define dispatch for the interface methods and also for equals, hashCode, and toString, which arrive as Object declarations. It handles a possibly null argument array for no-argument calls, decides how default interface methods are invoked, and unwraps InvocationTargetException when delegating reflectively. I state whether object methods use proxy identity, target semantics, or wrapper semantics and test equality symmetry. The selected loader must see every proxy interface, including the same interface identity used by callers. I also document interceptor order for logging, retries, transactions, and authorization because changing that order changes observable behavior.

read more Reflection
Was this clear?

Type system

2 questions
59 Why can Java create `List<?>[]` but not `List<String>[]`? Mid common reveal ▾ hide ▴

Arrays enforce their component type at runtime, so an array creation expression requires a reifiable component type. List<?> is reifiable because runtime checking needs to prove only that an element is some List. List is not: the array could check List but could not check String inside that list. If such an array existed, an Object[] alias could store a List, and failure would be delayed until a String read. I prefer nested collections and treat generic varargs with the same suspicion because the call is translated through an array.

read more Type erasure
Was this clear?
61 Why is `List<Integer>` not a subtype of `List<Number>`, and how does PECS recover safe flexibility? Mid common reveal ▾ hide ▴

Java generic types are invariant. If a List could be used as List, code holding the broader reference could add a Double and corrupt the integer list. A use-site wildcard exposes only operations safe for a family of types. List<? extends Number> accepts an integer list and produces values as Number, but rejects non-null additions. List<? super Integer> accepts Integer values, but produces only Object safely. For a copy API, I connect both directions with one T: the source extends T and the destination is super T.

Was this clear?

Debugging

1 question
60 How do you find the source of heap pollution when `ClassCastException` occurs much later? Senior occasional reveal ▾ hide ▴

I treat the throwing read as the endpoint, not necessarily the cause. The compiler inserted that cast because the receiving expression expected a parameterized element. I rebuild with unchecked and varargs warnings enabled, then trace raw assignments, unchecked casts, reflective results, deserialization boundaries, and generic arrays upstream. Every suppression must name the invariant that keeps the operation safe. A useful regression test inserts a value of the wrong type at the suspected boundary and follows the complete consumer path; merely asserting that the unchecked cast itself succeeds proves nothing.

read more Type erasure
Was this clear?