[{"data":1,"prerenderedAt":334},["ShallowReactive",2],{"topic-java-generics":3},{"framework":4,"topic":15,"subtopics":24},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Fjava.yml","Java interview questions on language fundamentals, object-oriented design, the Collections Framework, exception handling and concurrency — a staple of backend and enterprise technical interviews.","yml","java",{},"Java",5,"frameworks\u002Fjava",1,"jcUKEcQDoMZrreMRtZYJIVpkQlB-varlzbuwmzLr7kc",{"id":16,"description":17,"extension":7,"frameworkSlug":8,"meta":18,"name":19,"order":20,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Fjava-generics.yml","Type parameters, bounded types and wildcards (PECS) and the type erasure that underpins them — compile-time type safety for collections and APIs.",{},"Generics",3,"generics","topics\u002Fjava-generics","qD4bQH3YcT6lfgzLIroLr3wiNOaT1XQorSE8mv7sZWQ",[25,138,238],{"id":26,"title":27,"body":28,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":37,"navigation":38,"order":13,"path":39,"questions":40,"questionsCount":131,"related":132,"seo":133,"seoDescription":134,"stem":135,"subtopic":27,"topic":19,"topicSlug":21,"updated":136,"__hash__":137},"qa\u002Fjava\u002Fgenerics\u002Fgenerics-basics.md","Generics Basics",{"type":29,"value":30,"toc":31},"minimark",[],{"title":32,"searchDepth":33,"depth":33,"links":34},"",2,[],"medium","md",{},true,"\u002Fjava\u002Fgenerics\u002Fgenerics-basics",[41,46,50,54,58,62,66,70,74,78,82,87,91,95,99,103,107,111,115,119,123,127],{"id":42,"difficulty":43,"q":44,"a":45},"what-are-generics","easy","What are generics and what problem do they solve?","**Generics** let you parameterize a class, interface, or method by **type**,\nso the same code works for many types while the compiler still enforces type\nsafety. The two big wins are **compile-time type checking** (a wrong type is a\nbuild error, not a runtime crash) and **no manual casts** when you read values\nback out.\n\n```java\nList\u003CString> names = new ArrayList\u003C>();\nnames.add(\"Ada\");\nnames.add(42);            \u002F\u002F compile error — caught early\nString n = names.get(0);  \u002F\u002F no cast needed; compiler knows it's a String\n```\n\nBefore generics (Java 5), collections held raw `Object`, so you cast on every\n`get` and a wrong type blew up at runtime with `ClassCastException`. Generics\nmove that failure to **compile time**.\n",{"id":47,"difficulty":43,"q":48,"a":49},"generic-class","How do you declare a generic class?","You add a **type parameter** in angle brackets after the class name; that\nparameter then stands in for a real type everywhere inside the class. Callers\nsupply the actual type when they create an instance.\n\n```java\nclass Box\u003CT> {            \u002F\u002F T is the type parameter\n  private T value;\n  public void set(T v) { value = v; }\n  public T get() { return value; }\n}\n\nBox\u003CString> b = new Box\u003C>();\nb.set(\"hi\");\nString s = b.get();       \u002F\u002F returns T = String, no cast\n```\n\nThe type argument (`String`) replaces `T` for that instance, so the compiler\nrejects `b.set(42)` and lets `get()` return a `String` directly.\n",{"id":51,"difficulty":43,"q":52,"a":53},"type-parameter-naming","What are the conventional names for type parameters?","Type parameters are **single uppercase letters** by convention, each hinting at\na role:\n\n| Letter | Meaning |\n| ------ | ------- |\n| `T` | Type (the generic default) |\n| `E` | Element (used by collections) |\n| `K` | Key (maps) |\n| `V` | Value (maps) |\n| `N` | Number |\n| `R` | Return type (functional interfaces) |\n| `S`, `U` | second\u002Fthird types when more are needed |\n\n```java\ninterface Map\u003CK, V> { V get(K key); }   \u002F\u002F K = key, V = value\n```\n\nThese are pure convention — the compiler accepts any valid identifier — but\nfollowing them makes generic signatures instantly readable to other developers.\n",{"id":55,"difficulty":35,"q":56,"a":57},"generic-method","What is a generic method and how do you declare one?","A **generic method** declares its **own** type parameter, written before the\nreturn type. It can appear in any class (generic or not), and the type is scoped\nto that single method.\n\n```java\n\u002F\u002F \u003CT> introduces the type parameter for this method only\nstatic \u003CT> T firstOrNull(List\u003CT> list) {\n  return list.isEmpty() ? null : list.get(0);\n}\n\nString s = firstOrNull(List.of(\"a\", \"b\")); \u002F\u002F T inferred as String\nInteger n = firstOrNull(List.\u003CInteger>of()); \u002F\u002F T = Integer\n```\n\nThe `\u003CT>` between the modifiers and the return type is what makes it generic —\nwithout it, `T` would be an undefined symbol. The method's type parameter is\nindependent of any type parameter on the enclosing class.\n",{"id":59,"difficulty":35,"q":60,"a":61},"type-inference","How does the compiler infer type arguments for a generic method?","The compiler performs **type inference**: it looks at the **argument types** and\nthe **target type** (what the result is assigned to) to deduce the type\nparameter, so you rarely write it explicitly.\n\n```java\nstatic \u003CT> List\u003CT> singleton(T item) { return List.of(item); }\n\nvar xs = singleton(\"hi\");      \u002F\u002F T inferred from \"hi\" -> String\nList\u003CInteger> ys = singleton(7); \u002F\u002F T inferred -> Integer\n```\n\nWhen inference can't decide (or you want to override it), supply an **explicit\ntype witness** before the method name: `Collections.\u003CString>emptyList()`. This is\noccasionally needed when there are no arguments to infer from.\n",{"id":63,"difficulty":43,"q":64,"a":65},"diamond-operator","What is the diamond operator?","The **diamond operator** `\u003C>` (Java 7+) lets you omit the type arguments on the\nright side of an assignment; the compiler infers them from the **declared type**\non the left (the target type).\n\n```java\n\u002F\u002F verbose, pre-Java 7\nMap\u003CString, List\u003CInteger>> m = new HashMap\u003CString, List\u003CInteger>>();\n\n\u002F\u002F diamond — compiler infers \u003CString, List\u003CInteger>>\nMap\u003CString, List\u003CInteger>> m2 = new HashMap\u003C>();\n```\n\nIt cuts redundant boilerplate without losing any type safety — `new HashMap\u003C>()`\nis still fully generic, just inferred. Note `new HashMap()` (no diamond) is a\n**raw type** and is *not* the same thing.\n",{"id":67,"difficulty":43,"q":68,"a":69},"generic-interface","How do you define and implement a generic interface?","A generic interface declares type parameters just like a class. An implementor\neither **fixes** the type or **stays generic** by passing its own parameter\nthrough.\n\n```java\ninterface Repository\u003CT> {\n  void save(T item);\n  T findById(int id);\n}\n\n\u002F\u002F fix the type\nclass UserRepo implements Repository\u003CUser> {\n  public void save(User u) { }\n  public User findById(int id) { return null; }\n}\n\n\u002F\u002F stay generic\nclass MemRepo\u003CT> implements Repository\u003CT> { \u002F* ... *\u002F }\n```\n\nCore JDK interfaces like `Comparable\u003CT>`, `Iterable\u003CE>`, and `Comparator\u003CT>` work\nthis way, which is why `class Money implements Comparable\u003CMoney>` gives you a\ntype-safe `compareTo(Money)`.\n",{"id":71,"difficulty":43,"q":72,"a":73},"multiple-type-parameters","Can a generic type have more than one type parameter?","Yes — list them comma-separated inside the angle brackets. The classic example\nis `Map\u003CK, V>`, which is parameterized by both a **key** type and a **value**\ntype.\n\n```java\nclass Pair\u003CA, B> {\n  final A first;\n  final B second;\n  Pair(A a, B b) { first = a; second = b; }\n}\n\nPair\u003CString, Integer> p = new Pair\u003C>(\"age\", 30);\nString key = p.first;   \u002F\u002F A = String\nint val = p.second;     \u002F\u002F B = Integer\n```\n\nEach parameter is independent, so `Pair\u003CString, Integer>` and\n`Pair\u003CInteger, String>` are distinct, incompatible types.\n",{"id":75,"difficulty":35,"q":76,"a":77},"type-safety","How do generics improve type safety over Object?","Without generics you'd store everything as `Object`, deferring all type checking\nto **runtime casts** that can fail. Generics let the **compiler** verify types,\nturning a potential `ClassCastException` into a build error.\n\n```java\n\u002F\u002F pre-generics style\nList raw = new ArrayList();\nraw.add(\"hi\");\nInteger n = (Integer) raw.get(0);  \u002F\u002F compiles, ClassCastException at runtime\n\n\u002F\u002F generic style\nList\u003CString> safe = new ArrayList\u003C>();\nsafe.add(\"hi\");\nInteger m = safe.get(0);           \u002F\u002F compile error — caught immediately\n```\n\nThe cast disappears because the compiler already knows the element type, and it\ninserts any needed cast for you behind the scenes.\n",{"id":79,"difficulty":35,"q":80,"a":81},"raw-types","What is a raw type and why is it discouraged?","A **raw type** is a generic type used **without** its type argument, e.g. `List`\ninstead of `List\u003CString>`. It exists only for **backward compatibility** with\npre-Java-5 code, and using it **opts out of type safety** — the compiler can no\nlonger check element types.\n\n```java\nList raw = new ArrayList();   \u002F\u002F raw type\nraw.add(\"hi\");\nraw.add(42);                  \u002F\u002F no complaint — types unchecked\nString s = (String) raw.get(1); \u002F\u002F ClassCastException at runtime\n```\n\nRaw types produce **unchecked warnings** and re-introduce exactly the runtime\nfailures generics were designed to prevent. Always parameterize — use\n`List\u003CObject>` if you genuinely want any type, which keeps checking on.\n",{"id":83,"difficulty":84,"q":85,"a":86},"raw-vs-object","hard","What is the difference between List, List\u003CObject>, and List\u003C?>?","They look similar but behave very differently:\n\n| Type | Meaning | Type-checked? |\n| ---- | ------- | ------------- |\n| `List` | **raw** — legacy escape hatch | No (unchecked warnings) |\n| `List\u003CObject>` | a list that can hold **any** type | Yes |\n| `List\u003C?>` | a list of some **unknown** type | Yes (read-only) |\n\n```java\nList\u003CString> strings = new ArrayList\u003C>();\nList\u003CObject> objs = strings; \u002F\u002F compile error — not the same type\nList\u003C?> any = strings;       \u002F\u002F OK — wildcard accepts any List\u003CX>\nany.add(\"x\");                \u002F\u002F error — can't add to List\u003C?> (type unknown)\n```\n\nThe key trap: `List\u003CObject>` is **not** a supertype of `List\u003CString>` (generics\nare invariant), so you can't assign one to the other — that's where wildcards\ncome in.\n",{"id":88,"difficulty":84,"q":89,"a":90},"cannot-instantiate-type","Why can't you write new T() inside a generic class?","Because of **type erasure**, the type parameter `T` doesn't exist at runtime —\nthe JVM has no idea what concrete class to instantiate, so `new T()` is a compile\nerror. There's no constructor to call when `T` is unknown.\n\n```java\nclass Factory\u003CT> {\n  T create() {\n    return new T();          \u002F\u002F compile error — cannot instantiate T\n  }\n}\n```\n\nThe standard workaround is to pass a factory or a `Class\u003CT>` token and use\nreflection:\n\n```java\nT create(Class\u003CT> type) throws Exception {\n  return type.getDeclaredConstructor().newInstance();\n}\n```\n\n(Erasure has its own page — here it's enough to know `T` isn't a real runtime\ntype.)\n",{"id":92,"difficulty":84,"q":93,"a":94},"cannot-create-generic-array","Why can't you create a generic array like new T[]?","Arrays are **reified** — they know and check their element type at runtime —\nwhile generics are **erased**. Mixing the two would let an unchecked store slip\nthrough, so the compiler forbids `new T[]` and `new List\u003CString>[]`.\n\n```java\nclass Stack\u003CT> {\n  \u002F\u002F T[] data = new T[10];        \u002F\u002F compile error — generic array creation\n  Object[] data = new Object[10];  \u002F\u002F workaround: store as Object[]\n  @SuppressWarnings(\"unchecked\")\n  T get(int i) { return (T) data[i]; } \u002F\u002F cast on read\n}\n```\n\nThe common pattern is an `Object[]` backing store with a suppressed cast on\nread, which is exactly how `ArrayList` is implemented internally.\n",{"id":96,"difficulty":84,"q":97,"a":98},"generics-invariance","Why is List\u003CString> not a List\u003CObject>?","Generics are **invariant**: even though `String` is a subtype of `Object`,\n`List\u003CString>` is **not** a subtype of `List\u003CObject>`. If it were, you could\nbreak type safety by adding the wrong type through the supertype reference.\n\n```java\nList\u003CString> strings = new ArrayList\u003C>();\nList\u003CObject> objs = strings;   \u002F\u002F suppose this were allowed...\nobjs.add(42);                  \u002F\u002F ...then this would put an Integer in\nString s = strings.get(0);     \u002F\u002F ...and this would explode at runtime\n```\n\nThe compiler blocks the assignment to keep that from ever happening. Arrays, by\ncontrast, *are* covariant (`String[]` is an `Object[]`), which is exactly why\narray stores are checked at runtime and can throw `ArrayStoreException`.\n",{"id":100,"difficulty":35,"q":101,"a":102},"bounded-type-parameter","What is a bounded type parameter?","A **bound** restricts what types a parameter accepts using `extends`. `\u003CT extends\nNumber>` means \"any `T` that is `Number` or a subclass,\" which lets you call that\nbound's methods on `T`.\n\n```java\n\u002F\u002F T must be a Number, so .doubleValue() is available\nstatic \u003CT extends Number> double sum(List\u003CT> nums) {\n  double total = 0;\n  for (T n : nums) total += n.doubleValue();\n  return total;\n}\n\nsum(List.of(1, 2, 3));       \u002F\u002F OK — Integer extends Number\nsum(List.of(\"a\", \"b\"));      \u002F\u002F compile error — String isn't a Number\n```\n\n`extends` works for both classes and interfaces here, and you can require several\nbounds with `&` (`\u003CT extends Number & Comparable\u003CT>>`). Wildcards and more\nadvanced bounding are covered on the wildcards page.\n",{"id":104,"difficulty":35,"q":105,"a":106},"suppress-warnings-unchecked","When and how do you use @SuppressWarnings(\"unchecked\")?","`@SuppressWarnings(\"unchecked\")` silences the compiler's **unchecked** warnings —\nthe ones emitted when you do a cast or operation the compiler can't fully verify\nbecause of erasure. Use it only when you've **reasoned that the cast is safe**.\n\n```java\n@SuppressWarnings(\"unchecked\")           \u002F\u002F safe: we only ever store T here\nT get(int i) { return (T) data[i]; }\n```\n\nBest practice: put it on the **narrowest scope possible** (a single local\nvariable or method, never a whole class), and add a comment explaining why the\noperation is actually safe. Suppressing warnings blindly hides real bugs.\n",{"id":108,"difficulty":35,"q":109,"a":110},"var-with-generics","How does var interact with generics?","`var` infers the **full generic type** from the initializer, so you keep complete\ntype safety without repeating long parameter lists. But the initializer must\ncarry the type information — a bare diamond gives `var` nothing to infer.\n\n```java\nvar users = new HashMap\u003CString, List\u003CUser>>(); \u002F\u002F inferred fully\nvar first = users.get(\"a\");                     \u002F\u002F List\u003CUser>\n\nvar bad = new ArrayList\u003C>();   \u002F\u002F infers ArrayList\u003CObject> — probably not wanted\n```\n\nWith `var` the **right-hand side must specify the type arguments** (the diamond\ncan't borrow them from a left-hand declaration that no longer exists). So write\n`new ArrayList\u003CString>()`, not `new ArrayList\u003C>()`, when using `var`.\n",{"id":112,"difficulty":84,"q":113,"a":114},"generic-constructor","Can a constructor have its own type parameter?","Yes — a constructor can declare type parameters **independent** of the class's\nown, written before the constructor name. This is rare but valid when the\nconstructor needs a type only for its arguments.\n\n```java\nclass Holder\u003CT> {\n  private T value;\n  \u002F\u002F S is the constructor's own parameter, separate from class T\n  \u003CS extends T> Holder(S initial) {\n    this.value = initial;\n  }\n}\n```\n\nHere `S` is scoped to the constructor; the class is still `Holder\u003CT>`. Most code\njust reuses the class's `T`, but a generic constructor lets you accept a more\nspecific or unrelated type for construction only.\n",{"id":116,"difficulty":84,"q":117,"a":118},"static-generic-method","Why must a static method declare its own type parameter?","A static method belongs to the **class, not an instance**, so it **can't see the\nclass's type parameter** — that parameter only exists per object. A static method\nthat needs generics must declare its **own**.\n\n```java\nclass Box\u003CT> {\n  T value;\n  \u002F\u002F static \u003CT> needed — the class's T is not in scope here\n  static \u003CU> Box\u003CU> of(U v) {\n    Box\u003CU> b = new Box\u003C>();\n    b.value = v;\n    return b;\n  }\n}\n\nBox\u003CString> b = Box.of(\"hi\");   \u002F\u002F U inferred as String\n```\n\nUsing the class's `T` in a static method is a compile error precisely because\nthere's no instance to bind it to. (Naming the static parameter the same letter\nas the class's is legal but confusing — use a different letter.)\n",{"id":120,"difficulty":35,"q":121,"a":122},"generics-vs-erasure","At a high level, how do generics exist at runtime?","Java generics are a **compile-time** feature implemented by **type erasure**:\nthe compiler checks types and inserts casts, then **removes** the type\nparameters so the bytecode works on `Object` (or the bound). At runtime, a\n`List\u003CString>` and a `List\u003CInteger>` are just `List`.\n\n```java\nList\u003CString> a = new ArrayList\u003C>();\nList\u003CInteger> b = new ArrayList\u003C>();\nSystem.out.println(a.getClass() == b.getClass()); \u002F\u002F true — both ArrayList\n```\n\nThe benefit is **backward compatibility** with pre-generics bytecode; the cost\nis that types aren't available for reflection or runtime checks. The full\nmechanics and consequences live on the type-erasure page.\n",{"id":124,"difficulty":35,"q":125,"a":126},"why-not-primitives","Why can't you use primitives as type arguments?","Because of erasure, type parameters become `Object` at runtime, and primitives\naren't objects — so `List\u003Cint>` is illegal. You must use the **wrapper class**\n(`Integer`, `Double`, …), and autoboxing bridges the gap.\n\n```java\nList\u003Cint> nums;            \u002F\u002F compile error\nList\u003CInteger> nums2 = new ArrayList\u003C>();\nnums2.add(5);              \u002F\u002F autoboxed int -> Integer\nint x = nums2.get(0);      \u002F\u002F unboxed Integer -> int\n```\n\nThe trade-off is **boxing overhead** for large numeric collections, which is why\nspecialized primitive streams (`IntStream`) and libraries with primitive\ncollections exist. Project Valhalla aims to relax this in the future.\n",{"id":128,"difficulty":35,"q":129,"a":130},"comparable-generic","How does the Comparable\u003CT> interface use generics?","`Comparable\u003CT>` is generic so `compareTo` takes a **typed** argument instead of\nraw `Object` — no cast, and you can't accidentally compare against the wrong\ntype. You parameterize it with **your own class**.\n\n```java\nclass Version implements Comparable\u003CVersion> {\n  int number;\n  \u002F\u002F typed parameter — no casting from Object\n  public int compareTo(Version other) {\n    return Integer.compare(this.number, other.number);\n  }\n}\n```\n\nCompare this to the legacy raw `Comparable`, where `compareTo(Object o)` forced a\ndowncast. Bounding on `Comparable` (`\u003CT extends Comparable\u003CT>>`) is also how\nmethods like `Collections.max` guarantee their elements are orderable.\n",22,null,{"description":32},"Java generics interview questions — what generics are and why, generic classes and methods, type parameters, the diamond operator, type safety, raw types, and generic constructors.","java\u002Fgenerics\u002Fgenerics-basics","2026-06-20","RZvplRmyNsoceXctYSH0TDs9i3Jrl9pRwiY6A4Jnbjk",{"id":139,"title":140,"body":141,"description":32,"difficulty":84,"extension":36,"framework":10,"frameworkSlug":8,"meta":145,"navigation":38,"order":33,"path":146,"questions":147,"questionsCount":232,"related":132,"seo":233,"seoDescription":234,"stem":235,"subtopic":236,"topic":19,"topicSlug":21,"updated":136,"__hash__":237},"qa\u002Fjava\u002Fgenerics\u002Fwildcards-bounds.md","Wildcards Bounds",{"type":29,"value":142,"toc":143},[],{"title":32,"searchDepth":33,"depth":33,"links":144},[],{},"\u002Fjava\u002Fgenerics\u002Fwildcards-bounds",[148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228],{"id":149,"difficulty":35,"q":150,"a":151},"unbounded-wildcard","What is the unbounded wildcard \u003C?> and what does it mean?","The **unbounded wildcard** `\u003C?>` means \"a `List` of **some unknown type**\" —\nyou don't know or care which. It makes a generic method work over collections\nof *any* element type while staying type-safe, unlike a raw type.\n\n```java\nstatic void printAll(List\u003C?> list) {        \u002F\u002F any element type\n  for (Object o : list) System.out.println(o); \u002F\u002F safe: everything is an Object\n}\nprintAll(List.of(1, 2, 3));      \u002F\u002F List\u003CInteger> ok\nprintAll(List.of(\"a\", \"b\"));     \u002F\u002F List\u003CString> ok\n```\n\nBecause the element type is unknown, you **can read elements as `Object`** but\n**can't add** anything (except `null`) — the compiler can't prove your value\nmatches the hidden type. Use `\u003C?>` when the method body doesn't depend on the\nelement type at all.\n",{"id":153,"difficulty":84,"q":154,"a":155},"list-wildcard-vs-object-vs-raw","What is the difference between List\u003C?>, List\u003CObject> and a raw List?","They look similar but behave very differently:\n\n| Declaration | Accepts | Can add? | Type-safe? |\n| ----------- | ------- | -------- | ---------- |\n| `List\u003C?>` | any `List\u003CX>` | only `null` | yes |\n| `List\u003CObject>` | only `List\u003CObject>` | any object | yes |\n| `List` (raw) | any `List` | anything (unchecked) | no — legacy |\n\n```java\nList\u003CString> strs = new ArrayList\u003C>();\nList\u003C?> a = strs;        \u002F\u002F ok — unknown element type\nList\u003CObject> b = strs;   \u002F\u002F compile error — not the same type\nList c = strs;           \u002F\u002F ok but unchecked warnings; defeats generics\n```\n\n`List\u003CObject>` is a concrete type that only matches `List\u003CObject>`. `List\u003C?>`\nmatches *every* parameterization but is read-only. The **raw** `List` exists\nonly for pre-generics compatibility — it disables type checking, so avoid it.\n",{"id":157,"difficulty":35,"q":158,"a":159},"upper-bounded-wildcard","What is an upper-bounded wildcard \u003C? extends T>?","`\u003C? extends T>` means \"some **unknown subtype** of `T`\" — it sets an **upper\nbound**. It's used when you want to **read** `T` values out of a structure but\ndon't need to know the exact subtype.\n\n```java\nstatic double sum(List\u003C? extends Number> nums) { \u002F\u002F Number or any subtype\n  double total = 0;\n  for (Number n : nums) total += n.doubleValue(); \u002F\u002F safe: all are Numbers\n  return total;\n}\nsum(List.of(1, 2, 3));        \u002F\u002F List\u003CInteger> ok\nsum(List.of(1.5, 2.5));       \u002F\u002F List\u003CDouble> ok\n```\n\nEvery element is guaranteed to be **at least a `T`**, so reading as `T` is\nsafe. This is the **producer** side — the structure produces `T`s for you to\nconsume.\n",{"id":161,"difficulty":84,"q":162,"a":163},"why-cant-add-extends","Why can't you add to a List\u003C? extends Number>?","Because the compiler knows the list is `List\u003CSomeSubtypeOfNumber>` but **not\nwhich** subtype. It could be `List\u003CInteger>`, `List\u003CDouble>`, or anything else —\nso adding *any* concrete value might violate the real element type.\n\n```java\nList\u003C? extends Number> nums = new ArrayList\u003CInteger>();\nnums.add(1);        \u002F\u002F compile error — what if it's really List\u003CDouble>?\nnums.add(1.5);      \u002F\u002F compile error — what if it's really List\u003CInteger>?\nnums.add(null);     \u002F\u002F the only legal add — null fits any type\nNumber n = nums.get(0); \u002F\u002F reading is fine — guaranteed to be a Number\n```\n\nThe list becomes effectively **read-only** for element types. The rule:\n`extends` wildcards are for **getting**, not putting.\n",{"id":165,"difficulty":35,"q":166,"a":167},"lower-bounded-wildcard","What is a lower-bounded wildcard \u003C? super T>?","`\u003C? super T>` means \"some **unknown supertype** of `T`\" — it sets a **lower\nbound**. It's used when you want to **write** `T` values *into* a structure.\n\n```java\nstatic void addNumbers(List\u003C? super Integer> list) { \u002F\u002F Integer or any supertype\n  list.add(1);          \u002F\u002F safe — an Integer fits a List of Integer-or-wider\n  list.add(2);\n}\naddNumbers(new ArrayList\u003CInteger>()); \u002F\u002F ok\naddNumbers(new ArrayList\u003CNumber>());  \u002F\u002F ok — Integer fits a Number list\naddNumbers(new ArrayList\u003CObject>());  \u002F\u002F ok — Integer fits an Object list\n```\n\nWhatever the real type is, it's `Integer` or wider, so an `Integer` is always a\nvalid element. This is the **consumer** side — the structure consumes the `T`s\nyou supply.\n",{"id":169,"difficulty":84,"q":170,"a":171},"read-from-super-wildcard","What can you read back from a List\u003C? super T>?","Only **`Object`**. The compiler knows the list holds *some supertype* of `T`,\nbut the widest guaranteed common type of any supertype is `Object`, so that's\nall a `get` can be typed as.\n\n```java\nList\u003C? super Integer> list = new ArrayList\u003CNumber>();\nlist.add(42);              \u002F\u002F writing Integers is fine\nObject o = list.get(0);    \u002F\u002F ok — only Object is guaranteed\nInteger i = list.get(0);   \u002F\u002F compile error — could be a Number\u002FObject list\n```\n\nSo `super` wildcards are primarily for **putting in**; reading gives you back\nuntyped `Object`. This asymmetry with `extends` is exactly what PECS captures.\n",{"id":173,"difficulty":84,"q":174,"a":175},"pecs-principle","What is the PECS principle?","**PECS** = **Producer Extends, Consumer Super**. When a parameter **produces**\n`T`s for you (you read from it), use `\u003C? extends T>`. When it **consumes** `T`s\nyou give it (you write to it), use `\u003C? super T>`. The canonical example is a\n`copy` method:\n\n```java\n\u002F\u002F src PRODUCES elements -> extends; dest CONSUMES elements -> super\nstatic \u003CT> void copy(List\u003C? extends T> src, List\u003C? super T> dest) {\n  for (T t : src) dest.add(t);   \u002F\u002F read from src, write to dest\n}\nList\u003CInteger> ints = List.of(1, 2, 3);\nList\u003CNumber> dst = new ArrayList\u003C>();\ncopy(ints, dst);                 \u002F\u002F Integer producer -> Number consumer\n```\n\nThis is how `Collections.copy` is actually declared. PECS maximizes API\nflexibility: callers can pass a wider range of list types on each side.\n",{"id":177,"difficulty":84,"q":178,"a":179},"bounded-type-param-vs-wildcard","When should you use a bounded type parameter \u003CT extends Number> vs a wildcard?","Use a **bounded type parameter** when you need to **name the type** — to refer\nto it more than once, relate two arguments, or use it in the return type. Use a\n**wildcard** when the type is used only **once** and you never need to name it.\n\n```java\n\u002F\u002F type parameter: the SAME T links input and return\nstatic \u003CT extends Number> T firstOf(List\u003CT> list) { return list.get(0); }\n\n\u002F\u002F wildcard: type used once, never named\nstatic double sumOf(List\u003C? extends Number> list) { \u002F* ... *\u002F return 0; }\n```\n\nA good rule: if a wildcard would force you to invent a helper just to name the\ntype, use a type parameter instead. Otherwise prefer wildcards in API\nparameters — they read more cleanly to callers.\n",{"id":181,"difficulty":84,"q":182,"a":183},"multiple-bounds","How do multiple bounds \u003CT extends A & B> work?","A type parameter can require **several bounds** joined by `&`, meaning `T` must\nsatisfy **all** of them. At most **one can be a class**, and if present it must\ncome **first**; the rest must be interfaces.\n\n```java\n\u002F\u002F T must be both Comparable AND Serializable\nstatic \u003CT extends Comparable\u003CT> & Serializable> T maxOf(T a, T b) {\n  return a.compareTo(b) >= 0 ? a : b; \u002F\u002F can call Comparable methods on T\n}\n\n\u002F\u002F class first, then interfaces:\nstatic \u003CT extends Number & Comparable\u003CT>> T pick(T x) { return x; }\n```\n\nWithin the method `T` exposes the members of **all** bounds. Wildcards, by\ncontrast, allow only a **single** bound (`\u003C? extends A>`), so multiple bounds\nrequire a named type parameter.\n",{"id":185,"difficulty":84,"q":186,"a":187},"recursive-bound","Why does \u003CT extends Comparable\u003CT>> appear so often?","This is a **recursive (self-referential) type bound** — `T` must be comparable\n**to itself**. It captures the idea \"this type knows how to order its own\ninstances,\" which is exactly what sorting and min\u002Fmax need.\n\n```java\nstatic \u003CT extends Comparable\u003CT>> T max(List\u003CT> list) {\n  T best = list.get(0);\n  for (T t : list)\n    if (t.compareTo(best) > 0) best = t; \u002F\u002F t.compareTo(T) is type-safe\n  return best;\n}\nmax(List.of(3, 1, 2));        \u002F\u002F T = Integer, Integer implements Comparable\u003CInteger>\n```\n\nWithout the recursion you couldn't safely call `compareTo` with a `T` argument.\nThe real `Collections.max` uses `\u003CT extends Comparable\u003C? super T>>` — slightly\nlooser so a subtype can reuse an ancestor's comparison.\n",{"id":189,"difficulty":84,"q":190,"a":191},"wildcard-capture","What is wildcard capture and the capture-helper pattern?","**Wildcard capture** is the compiler giving the unknown type of a `\u003C?>` a\ntemporary name (shown in errors as `CAP#1`). Sometimes you need to *name* that\ntype to operate on it — the fix is a private **capture helper** generic method\nthat captures the wildcard into a real type variable.\n\n```java\n\u002F\u002F fails: compiler won't prove list.get(i) matches list.set(j, ...)\nstatic void swap(List\u003C?> list, int i, int j) {\n  swapHelper(list, i, j);                 \u002F\u002F delegate to capture the wildcard\n}\nprivate static \u003CT> void swapHelper(List\u003CT> list, int i, int j) {\n  T tmp = list.get(i);                    \u002F\u002F now there is a concrete T\n  list.set(i, list.get(j));\n  list.set(j, tmp);\n}\n```\n\nThe public method keeps the clean `\u003C?>` signature; the helper captures the\nwildcard as `T` so the body type-checks.\n",{"id":193,"difficulty":84,"q":194,"a":195},"array-covariance-generic-invariance","Why are arrays covariant but generics invariant?","Arrays are **covariant**: `String[]` *is a* `Object[]`. Generics are\n**invariant**: `List\u003CString>` is **not** a `List\u003CObject>`. Generics chose\ninvariance for **compile-time safety** — array covariance defers the check to\nruntime and can blow up.\n\n```java\nObject[] arr = new String[3];\narr[0] = 42;          \u002F\u002F compiles, throws ArrayStoreException at RUNTIME\n\nList\u003CObject> list = new ArrayList\u003CString>(); \u002F\u002F compile error — caught early\n```\n\nBecause generics are erased at runtime there's no `ArrayStore` check to fall\nback on, so the language forbids the unsafe assignment up front. **Wildcards**\nthen restore the lost flexibility safely (`List\u003C? extends Object>` accepts a\n`List\u003CString>` but won't let you put the wrong thing in).\n",{"id":197,"difficulty":35,"q":198,"a":199},"wildcards-restore-flexibility","How do wildcards restore the flexibility lost to invariance?","Invariance means `List\u003CInteger>` isn't a `List\u003CNumber>`, so a method taking\n`List\u003CNumber>` would reject an `Integer` list. A **wildcard** widens the\nparameter to accept a family of types while staying safe.\n\n```java\nstatic double total(List\u003CNumber> list) { \u002F* ... *\u002F return 0; }\ntotal(new ArrayList\u003CInteger>());      \u002F\u002F compile error — invariance\n\nstatic double total2(List\u003C? extends Number> list) { \u002F* ... *\u002F return 0; }\ntotal2(new ArrayList\u003CInteger>());     \u002F\u002F ok — wildcard accepts subtypes\ntotal2(new ArrayList\u003CDouble>());      \u002F\u002F ok\n```\n\nSo wildcards are the bridge between strict invariance and the polymorphism you\nactually want — you opt into covariance (`extends`) or contravariance (`super`)\nexactly where it's safe.\n",{"id":201,"difficulty":84,"q":202,"a":203},"collections-max-signature","Why is Collections.max declared with both extends and super wildcards?","Its signature is `static \u003CT extends Object & Comparable\u003C? super T>> T\nmax(Collection\u003C? extends T> coll)`. The two wildcards do different jobs:\n`Collection\u003C? extends T>` lets it accept any subtype collection (the collection\n**produces** `T`s), and `Comparable\u003C? super T>` lets a type be ordered by a\ncomparator **inherited from an ancestor**.\n\n```java\nclass Animal implements Comparable\u003CAnimal> { \u002F* ... *\u002F }\nclass Dog extends Animal { }\n\nList\u003CDog> dogs = List.of(new Dog(), new Dog());\nDog biggest = Collections.max(dogs); \u002F\u002F Dog uses Animal's Comparable\u003CAnimal>\n```\n\nThe `super` on `Comparable` is the key flexibility: `Dog` doesn't need its own\n`compareTo` — inheriting `Comparable\u003CAnimal>` suffices. This is PECS applied to\nthe comparison itself.\n",{"id":205,"difficulty":35,"q":206,"a":207},"addall-signature","How does Collection.addAll use wildcards?","`boolean addAll(Collection\u003C? extends E> c)` uses an **upper-bounded** wildcard\nbecause the source collection is a **producer** — `addAll` only **reads** from\n`c` and writes into `this`. That lets you add a collection of any subtype of\n`E`.\n\n```java\nList\u003CNumber> nums = new ArrayList\u003C>();\nList\u003CInteger> ints = List.of(1, 2, 3);\nnums.addAll(ints);     \u002F\u002F ok — Integer extends Number (producer)\n```\n\nWithout `? extends E` you could only pass an exact `Collection\u003CE>`, forcing\ncallers to convert. This is the \"Producer Extends\" half of PECS in the standard\nlibrary.\n",{"id":209,"difficulty":35,"q":210,"a":211},"cant-instantiate-wildcard","Can you use a wildcard when creating an object with new?","**No.** You can't write `new` with a wildcard type — the compiler needs a\nconcrete type argument to know what to construct. Wildcards are for **variable,\nparameter, and field types**, not instantiation.\n\n```java\nList\u003C?> ok = new ArrayList\u003CString>();   \u002F\u002F wildcard on the VARIABLE — fine\nList\u003C?> bad = new ArrayList\u003C?>();        \u002F\u002F compile error — can't instantiate \u003C?>\nvar list = new ArrayList\u003C>();            \u002F\u002F diamond infers \u003CObject>, not a wildcard\n```\n\nThe diamond `\u003C>` is **not** a wildcard — it tells the compiler to *infer* a\nconcrete type from context. A genuine `\u003C?>` has no concrete type to allocate, so\nconstruction is forbidden.\n",{"id":213,"difficulty":35,"q":214,"a":215},"wildcards-in-return-types","Why are wildcards discouraged in return types?","A wildcard in a **return type** leaks into the caller's code: they're forced to\ndeal with `\u003C?>` (read-only, capture errors) even though it gave them no\nflexibility. The advice (Effective Java) is to use wildcards on **parameters**,\nnot returns.\n\n```java\n\u002F\u002F bad: caller now holds a List\u003C?> they can barely use\nstatic List\u003C?> bad() { return new ArrayList\u003CString>(); }\n\n\u002F\u002F good: return a concrete or named type\nstatic \u003CT> List\u003CT> good(T seed) { return new ArrayList\u003C>(); }\n```\n\nIf a method's return type would need a wildcard, that's usually a sign it should\ntake a **type parameter** instead, so the caller gets a usable concrete type.\n",{"id":217,"difficulty":84,"q":218,"a":219},"nested-wildcards","How do nested wildcards like List\u003CList\u003C?>> behave?","Wildcards apply at **each level independently**. `List\u003CList\u003C?>>` is a list whose\nelements are each \"a list of some unknown type\" — and crucially that **outer\nlist is invariant**: it is *not* the same as `List\u003CList\u003CString>>`.\n\n```java\nList\u003CList\u003C?>> outer = new ArrayList\u003C>();\nouter.add(List.of(1, 2));        \u002F\u002F ok — inner is List\u003C? = Integer>\nouter.add(List.of(\"a\"));         \u002F\u002F ok — inner is List\u003C? = String>\n\nList\u003CList\u003CString>> strs = new ArrayList\u003C>();\nList\u003CList\u003C?>> alias = strs;      \u002F\u002F compile error — outer level is invariant\n```\n\nTo accept \"a list of lists of anything\" you need `List\u003C? extends List\u003C?>>` on\nthe outer level too. Mixing levels (`List\u003C? extends List\u003C? extends Number>>`) is\nlegal but a readability red flag.\n",{"id":221,"difficulty":84,"q":222,"a":223},"bounded-wildcard-vs-bounded-param-return","Why does a bounded type parameter, not a wildcard, let you return the element type?","A **wildcard has no name**, so you can't mention it in a return type — the best\nyou could return is `Object` or another wildcard. A **type parameter is named**,\nso it can appear in the return position and flow that exact type back to the\ncaller.\n\n```java\n\u002F\u002F wildcard: can't name the element type to return it\nstatic Number first(List\u003C? extends Number> l) { return l.get(0); } \u002F\u002F only Number\n\n\u002F\u002F type parameter: returns the caller's exact T\nstatic \u003CT extends Number> T firstTyped(List\u003CT> l) { return l.get(0); }\nInteger i = firstTyped(List.of(1, 2)); \u002F\u002F gets Integer back, not just Number\n```\n\nSo when the *output* type must match the *input* element type, a named bounded\ntype parameter is required.\n",{"id":225,"difficulty":84,"q":226,"a":227},"comparator-super-wildcard","Why do sort and Comparator parameters use \u003C? super T>?","A `Comparator\u003C? super T>` lets you sort a `List\u003CT>` with a comparator defined\nfor `T` **or any of its supertypes** — the comparator is a **consumer** of `T`s,\nso PECS says `super`. You shouldn't be forced to write a `T`-specific comparator\nwhen an ancestor's already works.\n\n```java\n\u002F\u002F List.sort signature: void sort(Comparator\u003C? super E> c)\nList\u003CDog> dogs = new ArrayList\u003C>(\u002F* ... *\u002F);\nComparator\u003CAnimal> byAge = Comparator.comparingInt(Animal::age);\ndogs.sort(byAge);     \u002F\u002F ok — a Comparator\u003CAnimal> can compare Dogs (super)\n```\n\nWithout `super` you'd have to duplicate `byAge` as a `Comparator\u003CDog>`. This\n\"Consumer Super\" usage is one of the most common real-world wildcard payoffs.\n",{"id":229,"difficulty":35,"q":230,"a":231},"get-put-principle","What is the get-and-put principle and how does it relate to PECS?","The **get-and-put principle** is the same rule as PECS stated mechanically:\nuse `extends` when you only **get** values out, use `super` when you only\n**put** values in, and use an **exact type** (no wildcard) when you need to do\n**both**.\n\n```java\nList\u003C? extends Number> producer = List.of(1, 2);\nNumber n = producer.get(0);   \u002F\u002F get: ok    | put: forbidden\n\nList\u003C? super Integer> consumer = new ArrayList\u003CNumber>();\nconsumer.add(7);              \u002F\u002F put: ok     | get returns only Object\n\nList\u003CInteger> both = new ArrayList\u003C>();\nboth.add(7); int x = both.get(0); \u002F\u002F exact type: get AND put both work\n```\n\nSo if a method must read *and* write the same element type, drop the wildcard\nand use a concrete type or a named type parameter.\n",21,{"description":32},"Java generics wildcards interview questions — unbounded, upper- and lower-bounded wildcards, the PECS principle, bounded type parameters, multiple bounds, and wildcard capture.","java\u002Fgenerics\u002Fwildcards-bounds","Wildcards & Bounded Types","Q4MMlXMr2OlzLlAypo6k565_DfRC63kkkhC4vyNUgmM",{"id":239,"title":240,"body":241,"description":32,"difficulty":84,"extension":36,"framework":10,"frameworkSlug":8,"meta":245,"navigation":38,"order":20,"path":246,"questions":247,"questionsCount":232,"related":132,"seo":330,"seoDescription":331,"stem":332,"subtopic":240,"topic":19,"topicSlug":21,"updated":136,"__hash__":333},"qa\u002Fjava\u002Fgenerics\u002Ftype-erasure.md","Type Erasure",{"type":29,"value":242,"toc":243},[],{"title":32,"searchDepth":33,"depth":33,"links":244},[],{},"\u002Fjava\u002Fgenerics\u002Ftype-erasure",[248,252,256,260,264,268,272,275,278,282,286,290,294,298,302,306,310,314,318,322,326],{"id":249,"difficulty":35,"q":250,"a":251},"what-is-type-erasure","What is type erasure in Java generics?","**Type erasure** is the process by which the compiler **removes all generic\ntype information** during compilation. Generics exist only at **compile time**\nfor type checking; at runtime the type parameters are gone, so a\n`List\u003CString>` and a `List\u003CInteger>` are both just plain `List`.\n\n```java\nList\u003CString> a = new ArrayList\u003C>();\nList\u003CInteger> b = new ArrayList\u003C>();\nSystem.out.println(a.getClass() == b.getClass()); \u002F\u002F true — both ArrayList\n```\n\nThe compiler replaces type parameters with their **bound** (or `Object` if\nunbounded) and inserts casts where needed. The result is bytecode that looks\nessentially like pre-generics Java. **Rule of thumb:** generics are a\ncompile-time fiction — nothing about the type argument survives to runtime.\n",{"id":253,"difficulty":35,"q":254,"a":255},"why-type-erasure","Why did Java implement generics using type erasure?","The driving reason was **backward compatibility**. Generics arrived in Java 5,\nlong after millions of lines of pre-generics code existed. Erasure let\ngeneric code and legacy raw-type code **interoperate** on the same JVM without\nchanging the bytecode format or breaking existing libraries.\n\n```java\nList\u003CString> generic = new ArrayList\u003C>();\nList raw = generic;          \u002F\u002F legacy raw type — still works\nraw.add(\"ok\");               \u002F\u002F unchecked, but compiles and runs\n```\n\nA pre-generics `.class` file and a generics-aware one produce **compatible**\nbytecode, and a `List` from old code can flow into new generic code.\n**Rule of thumb:** erasure was the price of adding generics without forking\nthe platform — runtime reification (like C#) would have broken the existing\necosystem.\n",{"id":257,"difficulty":84,"q":258,"a":259},"how-compiler-erases","How exactly does the compiler erase generic types?","The compiler applies three transformations: it **replaces type parameters**\nwith their leftmost bound (or `Object` if unbounded), **inserts casts** at\nevery site where erased values are read out, and **generates bridge methods**\nto preserve polymorphism. The runtime never sees `T`.\n\n```java\n\u002F\u002F You write:\nclass Box\u003CT> { T value; T get() { return value; } }\nString s = new Box\u003CString>().get();\n\n\u002F\u002F After erasure (conceptually):\nclass Box { Object value; Object get() { return value; } }\nString s = (String) new Box().get();   \u002F\u002F compiler inserts the cast\n```\n\nA bounded `\u003CT extends Number>` erases to `Number`, not `Object`.\n**Rule of thumb:** type parameter -> bound, plus compiler-inserted casts — the\ncasts are guaranteed safe because the compiler already type-checked the code.\n",{"id":261,"difficulty":35,"q":262,"a":263},"erasure-to-bound","What does a bounded type parameter erase to?","A type parameter erases to its **leftmost (first) bound**, not always `Object`.\nAn unbounded `\u003CT>` erases to `Object`, but `\u003CT extends Number>` erases to\n`Number`, which lets the compiler call `Number` methods directly on `T`.\n\n```java\n\u003CT extends Number> double sum(T a, T b) {\n  return a.doubleValue() + b.doubleValue(); \u002F\u002F legal — T erases to Number\n}\n\u002F\u002F erased signature: double sum(Number a, Number b)\n\n\u003CT extends Comparable\u003CT> & Serializable> T pick(T x) { return x; }\n\u002F\u002F erases to Comparable (the FIRST bound)\n```\n\nWith multiple bounds (`A & B`), only the **first** drives erasure; that's why\nyou put the class or most-used interface first. **Rule of thumb:** the erased\ntype is the first bound — choose bound order so the useful methods survive.\n",{"id":265,"difficulty":84,"q":266,"a":267},"reifiable-vs-non-reifiable","What is the difference between reifiable and non-reifiable types?","A **reifiable** type is one whose type information is **fully available at\nruntime** — its representation is complete after erasure. A **non-reifiable**\ntype loses information to erasure, so the JVM can't fully reconstruct it.\n\n| Reifiable (survives) | Non-reifiable (erased) |\n| -------------------- | ---------------------- |\n| `String`, `Integer` | `List\u003CString>` |\n| `List`, `Map` (raw) | `List\u003C? extends Number>` |\n| `List\u003C?>` (unbounded wildcard) | `T` (type parameter) |\n| `int[]`, `String[]` | `List\u003CString>[]` |\n\n```java\no instanceof List\u003C?>      \u002F\u002F legal — unbounded wildcard is reifiable\no instanceof List\u003CString> \u002F\u002F ERROR — non-reifiable, info was erased\n```\n\n**Rule of thumb:** if a type still carries a generic argument other than `?`,\nit's non-reifiable and you can't use it with `instanceof`, array creation, or\n`.class`.\n",{"id":269,"difficulty":35,"q":270,"a":271},"no-class-literal","Why is List\u003CString>.class not allowed?","Because there is only **one `Class` object** for `List`, shared by every\nparameterization. After erasure `List\u003CString>`, `List\u003CInteger>`, and raw\n`List` are the same class, so a `List\u003CString>.class` literal would be\nmeaningless — there's nothing distinct to point to.\n\n```java\nClass\u003C?> c = List.class;          \u002F\u002F legal — the one List class\nClass\u003C?> d = List\u003CString>.class;  \u002F\u002F compile error\nList\u003CString> a = new ArrayList\u003C>();\nList\u003CInteger> b = new ArrayList\u003C>();\nSystem.out.println(a.getClass() == b.getClass()); \u002F\u002F true\n```\n\n`getClass()` on any generic instance returns the **raw** class object for the\nsame reason. **Rule of thumb:** there's one `Class` per erased type, so a\nparameterized class literal can't exist.\n",{"id":273,"difficulty":84,"q":89,"a":274},"cannot-instantiate-t","Because at runtime `T` has been erased — the JVM has **no idea which class** to\ninstantiate, and it can't guarantee `T` even has a no-arg constructor. The\n`new` bytecode needs a concrete class, which erasure has removed.\n\n```java\nclass Factory\u003CT> {\n  T make() { return new T(); }   \u002F\u002F compile error — cannot instantiate T\n}\n\n\u002F\u002F Workaround: pass a Class token or a supplier\nclass Factory\u003CT> {\n  T make(Class\u003CT> type) throws Exception {\n    return type.getDeclaredConstructor().newInstance(); \u002F\u002F reflection\n  }\n  T make(Supplier\u003CT> s) { return s.get(); }             \u002F\u002F cleaner\n}\n```\n\n**Rule of thumb:** to create instances of a type parameter, pass in a\n`Class\u003CT>` token or a `Supplier\u003CT>` — the type must come from somewhere\nreifiable.\n",{"id":92,"difficulty":84,"q":276,"a":277},"Why can't you create a generic array like new T[] or new List\u003CString>[]?","Arrays are **reified** — they remember and **enforce their element type at\nruntime** (storing a wrong type throws `ArrayStoreException`). Generics are\n**erased**. The two models are incompatible: a generic array couldn't perform\nits runtime store-check because the element type was erased.\n\n```java\nT[] a = new T[10];               \u002F\u002F compile error — generic array creation\nList\u003CString>[] b = new List\u003CString>[10]; \u002F\u002F compile error\n\n\u002F\u002F Workarounds:\nList\u003CString>[] c = (List\u003CString>[]) new List[10]; \u002F\u002F unchecked cast\nT[] d = (T[]) Array.newInstance(componentType, 10); \u002F\u002F reflection + Class token\n```\n\n**Rule of thumb:** you can't directly create arrays of a non-reifiable type;\nuse a `List\u003CList\u003CString>>` or an unchecked cast from a raw array.\n",{"id":279,"difficulty":84,"q":280,"a":281},"heap-pollution","What is heap pollution and how do generic arrays cause it?","**Heap pollution** occurs when a variable of a parameterized type points to an\nobject that is **not** of that type — usually because erasure let an\nincompatible value slip in. Generic arrays are banned precisely because they'd\nmake this trivially easy and undetectable.\n\n```java\nList\u003CString>[] arr = (List\u003CString>[]) new List[1]; \u002F\u002F unchecked\nObject[] objs = arr;                  \u002F\u002F arrays are covariant\nobjs[0] = List.of(42);                \u002F\u002F stores List\u003CInteger> — no error!\nString s = arr[0].get(0);             \u002F\u002F ClassCastException at READ time\n```\n\nThe corruption is silent until a later read fails far from the cause.\n**Rule of thumb:** heap pollution = a generic variable holding the wrong\nelement type; it surfaces as a surprise `ClassCastException` from\ncompiler-inserted casts.\n",{"id":283,"difficulty":35,"q":284,"a":285},"instanceof-generics","Why can't you use instanceof with a parameterized type?","`instanceof` is a **runtime** check, but the generic type argument was\n**erased**, so there's nothing to test against. The JVM could only tell you\nit's a `List`, never a `List\u003CString>`. Only **reifiable** types (raw types or\nthe unbounded wildcard) are allowed.\n\n```java\nif (obj instanceof List\u003CString>) { } \u002F\u002F compile error\nif (obj instanceof List\u003C?>) { }       \u002F\u002F OK — unbounded wildcard is reifiable\nif (obj instanceof List) { }          \u002F\u002F OK — raw type\n\n@SuppressWarnings(\"unchecked\")\nList\u003CString> l = (List\u003CString>) obj;  \u002F\u002F cast compiles but is unchecked\n```\n\n**Rule of thumb:** check against `List\u003C?>` or the raw `List`; you can never\n`instanceof` a specific type argument because it doesn't exist at runtime.\n",{"id":287,"difficulty":84,"q":288,"a":289},"bridge-methods","What are bridge methods and why does the compiler generate them?","A **bridge method** is a synthetic method the compiler generates to **preserve\npolymorphism** after erasure. When a generic supertype's method erases to a\ndifferent signature than the subtype's override, the compiler adds a bridge so\ndynamic dispatch still finds the real method.\n\n```java\nclass Node\u003CT> { void set(T t) { } }            \u002F\u002F erases to set(Object)\nclass StringNode extends Node\u003CString> {\n  @Override void set(String s) { }             \u002F\u002F set(String)\n}\n\u002F\u002F Compiler adds a synthetic bridge in StringNode:\n\u002F\u002F void set(Object o) { set((String) o); }      \u002F\u002F forwards to the real method\n```\n\nWithout the bridge, `Node\u003CString> n = new StringNode(); n.set(\"x\")` would call\nthe inherited `set(Object)` and skip the override. **Rule of thumb:** bridge\nmethods are invisible glue that keep overriding working across erased generic\nsignatures.\n",{"id":291,"difficulty":35,"q":292,"a":293},"bridge-method-visibility","How can you tell a bridge method apart from a real one?","Bridge methods are marked **synthetic** and carry the **`ACC_BRIDGE`** flag in\nthe bytecode. You can detect them at runtime via reflection with\n`Method.isBridge()` and `Method.isSynthetic()`. They never appear in your\nsource and you shouldn't call them directly.\n\n```java\nfor (Method m : StringNode.class.getDeclaredMethods()) {\n  System.out.println(m + \" bridge=\" + m.isBridge());\n}\n\u002F\u002F set(String) bridge=false\n\u002F\u002F set(Object) bridge=true   \u003C- the synthetic bridge\n```\n\nThey're why reflective scans sometimes find \"duplicate\" methods that differ\nonly by parameter type. **Rule of thumb:** filter out `isBridge()`\u002F\n`isSynthetic()` methods when introspecting generic classes.\n",{"id":295,"difficulty":84,"q":296,"a":297},"overload-clash","Why won't two methods that differ only by generic type parameter compile?","Because after erasure they have the **same signature**, and a class can't have\ntwo methods with identical signatures. The compiler reports a **\"name clash\"**\neven though the source-level parameter types look different.\n\n```java\nclass Printer {\n  void print(List\u003CString> s) { }   \u002F\u002F erases to print(List)\n  void print(List\u003CInteger> i) { }  \u002F\u002F also erases to print(List) — CLASH!\n}\n\u002F\u002F error: name clash: both methods have the same erasure\n```\n\nThe fix is to give them genuinely different erased signatures (different raw\ntypes or arity) or rename one. **Rule of thumb:** overloads must differ after\nerasure — distinct type arguments alone are not enough.\n",{"id":299,"difficulty":84,"q":300,"a":301},"class-token-pattern","What is the Class\u003CT> type token pattern and why is it useful?","A **type token** is a `Class\u003CT>` object passed in to **recover the type\ninformation** that erasure removed. Since the type argument is gone at runtime,\nhanding the method a `Class\u003CT>` lets it instantiate, cast, or check types\nsafely.\n\n```java\n\u003CT> T fromJson(String json, Class\u003CT> type) {\n  Object parsed = parse(json);\n  return type.cast(parsed);          \u002F\u002F typed cast via the token\n}\nUser u = fromJson(s, User.class);     \u002F\u002F T inferred from the token\n\n\u003CT> T create(Class\u003CT> type) throws Exception {\n  return type.getDeclaredConstructor().newInstance();\n}\n```\n\nFrameworks like Jackson and Spring rely on this everywhere.\n**Rule of thumb:** when you need the runtime type of `T`, pass a `Class\u003CT>`\ntoken — it's the standard escape hatch from erasure.\n",{"id":303,"difficulty":84,"q":304,"a":305},"super-type-token","How do super type tokens (TypeReference) capture generic types at runtime?","A plain `Class\u003CT>` token can't represent a **parameterized** type like\n`List\u003CString>` (no such class literal). The **super type token** trick (used by\nJackson's `TypeReference`, Guava's `TypeToken`) captures it by subclassing an\nabstract generic class and reading the type argument via reflection from the\n**generic superclass**, which the compiler *does* record.\n\n```java\n\u002F\u002F The anonymous subclass embeds List\u003CString> in its signature:\nTypeReference\u003CList\u003CString>> ref = new TypeReference\u003CList\u003CString>>() {};\n\u002F\u002F Internally:\nType t = getClass().getGenericSuperclass();           \u002F\u002F TypeReference\u003CList\u003CString>>\nType arg = ((ParameterizedType) t).getActualTypeArguments()[0]; \u002F\u002F List\u003CString>\n```\n\nGeneric type info on **class\u002Fmethod signatures** survives erasure (in metadata),\neven though instance-level arguments don't. **Rule of thumb:** subclassing a\ngeneric type pins its arguments in the class signature, which reflection can\nread back.\n",{"id":307,"difficulty":35,"q":308,"a":309},"static-field-no-type-param","Why can't a static field or static context use the class type parameter?","A type parameter belongs to a **specific instance's** parameterization, but a\n**static** member is shared across **all** parameterizations — and after\nerasure there's only one class anyway. There's no single `T` for the static\ncontext to refer to, so it's forbidden.\n\n```java\nclass Box\u003CT> {\n  static T shared;              \u002F\u002F compile error — T in static context\n  static void set(T t) { }      \u002F\u002F compile error\n  static \u003CU> U pick(U u) { return u; } \u002F\u002F OK — its OWN type parameter\n}\n```\n\nA static **method** may declare its **own** type parameter, which is fine.\n**Rule of thumb:** the class's `T` is per-instance; statics are class-wide, so\nthey can't use it — give a static method its own type parameter instead.\n",{"id":311,"difficulty":84,"q":312,"a":313},"generic-exceptions","What are the restrictions on generics with exceptions?","A generic class **cannot extend `Throwable`**, and you **cannot catch a type\nparameter**, because `catch` is a runtime dispatch on the exception's actual\nclass — which erasure has removed. You *can* declare a method that **throws**\na type parameter bounded by `Throwable`.\n\n```java\nclass MyException\u003CT> extends Exception { }  \u002F\u002F compile error — generic Throwable\n\n\u003CT extends Throwable> void run() {\n  try { \u002F* ... *\u002F }\n  catch (T e) { }              \u002F\u002F compile error — cannot catch type parameter\n}\n\n\u003CT extends Throwable> void rethrow(T t) throws T { throw t; } \u002F\u002F OK\n```\n\nIf catch were allowed, two `catch (T)` clauses could erase to the same\n`catch (Exception)`. **Rule of thumb:** you can throw but never catch a type\nparameter, and exception classes can't be generic.\n",{"id":315,"difficulty":35,"q":316,"a":317},"runtime-type-info-survives","What generic type information actually survives erasure?","Instance type arguments vanish, but generic info embedded in **declarations** is\nkept in the class file's signature metadata and is readable via reflection\n(`java.lang.reflect.Type`). This includes field types, method\nparameter\u002Freturn types, type variable bounds, and the **generic superclass \u002F\ninterfaces**.\n\n```java\nclass Repo { List\u003CString> names; }\nField f = Repo.class.getDeclaredField(\"names\");\nType t = f.getGenericType();                 \u002F\u002F List\u003CString> — preserved!\nParameterizedType pt = (ParameterizedType) t;\nSystem.out.println(pt.getActualTypeArguments()[0]); \u002F\u002F class java.lang.String\n```\n\nWhat's lost is the argument of a **runtime object** (`new ArrayList\u003CString>()`\nknows nothing about `String`). **Rule of thumb:** declaration-site generics\nlive in metadata; use-site instance generics do not.\n",{"id":319,"difficulty":35,"q":320,"a":321},"safevarargs","What does @SafeVarargs do and how does it relate to erasure?","A **varargs parameter of a generic type** creates a generic array under the\nhood (`T...` becomes `T[]`), which triggers an unavoidable **unchecked \u002F\n\"possible heap pollution\"** warning. `@SafeVarargs` is your assertion that the\nmethod **only reads** from the varargs and never pollutes the array, which\nsuppresses the warning at the declaration and all call sites.\n\n```java\n@SafeVarargs\nstatic \u003CT> List\u003CT> listOf(T... items) {   \u002F\u002F T[] is a non-reifiable array\n  return new ArrayList\u003C>(Arrays.asList(items)); \u002F\u002F safe — read only\n}\n```\n\nIt's applicable only to methods that **can't be overridden** (`static`,\n`final`, or `private`). **Rule of thumb:** use `@SafeVarargs` when your\ngeneric varargs method is read-only and provably safe from heap pollution.\n",{"id":323,"difficulty":35,"q":324,"a":325},"unchecked-warnings","What is an unchecked warning and why does erasure cause it?","An **unchecked warning** means the compiler **can't verify the type safety** of\nan operation because the needed type information was erased — typically a cast\nto a parameterized type or use of a raw type. The code compiles, but the\ncompiler is telling you it can't guarantee the runtime cast won't fail.\n\n```java\nObject o = new ArrayList\u003CString>();\nList\u003CString> list = (List\u003CString>) o; \u002F\u002F unchecked — only List is verifiable\n\nList raw = new ArrayList();\nraw.add(\"x\");                          \u002F\u002F unchecked call to add(E)\n```\n\nSuppress only when you've manually proven safety, with the **narrowest scope**\nand a comment, via `@SuppressWarnings(\"unchecked\")`. **Rule of thumb:** an\nunchecked warning is erasure admitting it can't check you — treat each one as a\npotential `ClassCastException` to justify.\n",{"id":327,"difficulty":84,"q":328,"a":329},"erasure-vs-reification","How does Java's erasure differ from reified generics in languages like C#?","With **reified generics** (C#\u002F.NET), the type argument is **preserved at\nruntime**: `List\u003Cint>` and `List\u003Cstring>` are distinct types, you can call\n`typeof(T)`, do `new T()`, and use `is List\u003Cstring>`. Java's **erased**\ngenerics throw all of that away after compilation.\n\n```java\n\u002F\u002F Java — none of these work:\nT.class;  new T();  new T[10];  obj instanceof List\u003CString>;\n\n\u002F\u002F C# equivalents all work because T is reified at runtime.\n```\n\nReification costs a specialized type per parameterization and breaks legacy\ninterop; erasure is cheaper and compatible but loses runtime type identity.\n**Rule of thumb:** Java traded runtime type knowledge for backward\ncompatibility — every generics restriction you hit traces back to that choice.\n",{"description":32},"Java type erasure interview questions — how the compiler erases generics, bridge methods, reifiable vs non-reifiable types, generics and arrays, restrictions on generics, and runtime type information.","java\u002Fgenerics\u002Ftype-erasure","Rh7iwMUxEBeSRusc_Z0L9khTTqt-GzkevYFbBvte82E",1782244097158]