What instanceof and cast operations are restricted by reifiability, and why?
answer
- instanceof needs reifiable type
- x instanceof List<String> = compile error
- Use instanceof List<?> or raw List
- Cast to List<String> = unchecked warning
- Heap pollution -> ClassCastException later
basics
~20 sYou can only use instanceof with reifiable types. 'x instanceof List<String>' is a compile error because the <String> is erased and can't be checked at runtime; use 'x instanceof List<?>' or raw 'List' instead. Casts to List<String> compile but give an 'unchecked' warning.
solid answer
~50 s`instanceof` performs a runtime type test, so it only works on types the runtime fully knows — reifiable types. `x instanceof List<String>` is rejected at compile time because after erasure there is no `String` info to test; the legal forms are `x instanceof List<?>` or `x instanceof List` (raw), both reifiable. Casts behave differently: a cast *to* a non-reifiable type like `(List<String>) obj` does compile, but the compiler can only verify the erased part (`List`), so it emits an **unchecked cast** warning — at runtime it's effectively a cast to `List`, and a wrong element won't be caught until you pull it out and it fails with `ClassCastException` (heap pollution). So reifiability gates `instanceof` outright, and downgrades non-reifiable casts to unchecked. Best practice: test/cast against `List<?>` when you only need 'is it a list', and avoid relying on unchecked casts.
code
java · 11 linesObject x = new ArrayList<Integer>();
// if (x instanceof List<String>) {} // COMPILE ERROR: non-reifiable
if (x instanceof List<?> list) { // OK: reifiable wildcard form
System.out.println(list.size());
}
@SuppressWarnings("unchecked")
List<String> ls = (List<String>) x; // compiles with unchecked warning
// Runtime check only confirms it's a List, not a List<String>:
String s = ls.get(0); // ClassCastException (heap pollution)go deeper
Knows instanceof List<String> doesn't compile and that you'd write instanceof List<?> instead.
Explains erasure as the reason, knows the legal instanceof forms, and that casts to List<String> give an unchecked warning.
Explains heap pollution and the deferred ClassCastException, when an unchecked cast is acceptable, and how to scope @SuppressWarnings.
Frames the runtime-verifiability invariant across instanceof/cast/array-store, and sets team policy on unchecked warnings, safe-cast utilities, and avoiding raw types.
## What instanceof and cast actually do at runtime - `x instanceof SomeType` asks the JVM, at runtime, 'is the object referenced by `x` an instance of `SomeType`?' It returns a boolean. - `(SomeType) x` is a *checked cast*: the JVM verifies at runtime that `x` really is a `SomeType`, throwing `ClassCastException` if not. Both need **real runtime type information**. After **type erasure** (the compiler removes generic type arguments), the only generic info left is the raw class. So these operations can only fully work on **reifiable** types. ## instanceof: restricted to reifiable types The JLS forbids `instanceof` against a non-reifiable type: ```java if (x instanceof List<String>) { ... } // COMPILE ERROR ``` There is no `String` at runtime to test, so the check is meaningless — the compiler rejects it rather than let you write a test that can't mean what it says. Legal forms: ```java if (x instanceof List<?>) { ... } // OK: List<?> is reifiable if (x instanceof List) { ... } // OK (raw), but raw-type warning ``` With pattern matching, `x instanceof List<?> list` is the idiomatic modern form. Note: `x instanceof List<?>` only tells you 'it's some kind of List' — it cannot tell you the element type. ## Casts: non-reifiable casts compile but are 'unchecked' Casting *to* a non-reifiable type is allowed but only partially verifiable: ```java Object o = new ArrayList<Integer>(); List<String> ls = (List<String>) o; // compiles, 'unchecked cast' WARNING ``` At runtime the JVM can only check the erased part — that `o` is a `List`. It cannot check that it's a `List<String>`. So the cast 'succeeds' even though the list actually holds `Integer`s. This is **heap pollution**: a variable of type `List<String>` now references a list with the wrong elements. The error surfaces later, away from the cast: ```java String s = ls.get(0); // ClassCastException here, not at the cast ``` The **unchecked warning** is the compiler telling you: 'I verified what I could; the rest is on you.' ## Why downcasting a generic collection is dangerous A `(List<String>) someList` cast is exactly this unchecked situation — there's no way to confirm the elements. Prefer designs that don't need it; if you must, isolate it and document why it's safe (e.g. you created the list yourself). ## Reifiable casts are fully checked Casting to a reifiable type is fully verified, no warning: ```java Object o = ...; List<?> anyList = (List<?>) o; // fully checked, no warning String str = (String) o; // fully checked ``` ## Summary table | Operation | Reifiable target | Non-reifiable target | |---|---|---| | `instanceof` | allowed | compile error | | cast | fully checked, no warning | compiles, unchecked warning (partial check) | The unifying rule: anything that needs to *verify a type at runtime* can only fully do so for reifiable types, because erasure removed everything else.
- What is 'heap pollution'?When a variable of a parameterized type (e.g. List<String>) refers to an object that isn't of that type (e.g. a list of Integers), usually via an unchecked cast or generic varargs. It causes ClassCastException later when an element is retrieved.
- Does (List<String>) obj throw at the cast site if obj is a List<Integer>?No. The runtime only checks the erased type (List), which matches, so the cast succeeds. The ClassCastException happens later when you read an element and it's not a String.
saying these in an interview costs you the question
- Thinking (List<String>) cast is verified at runtime — only the erased List part is
- Believing x instanceof List<?> tells you the element type — it doesn't
- Saying instanceof List<String> just returns false — it doesn't compile at all
- Treating an unchecked-cast warning as harmless noise to blanket-suppress