[{"data":1,"prerenderedAt":134},["ShallowReactive",2],{"qa-\u002Fjava\u002Fgenerics\u002Fgenerics-basics":3},{"page":4,"siblings":122,"blog":131},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":113,"related":114,"seo":115,"seoDescription":116,"stem":117,"subtopic":6,"topic":118,"topicSlug":119,"updated":120,"__hash__":121},"qa\u002Fjava\u002Fgenerics\u002Fgenerics-basics.md","Generics Basics",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","Java","java",{},true,1,"\u002Fjava\u002Fgenerics\u002Fgenerics-basics",[23,28,32,36,40,44,48,52,56,60,64,69,73,77,81,85,89,93,97,101,105,109],{"id":24,"difficulty":25,"q":26,"a":27},"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":29,"difficulty":25,"q":30,"a":31},"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":33,"difficulty":25,"q":34,"a":35},"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":37,"difficulty":14,"q":38,"a":39},"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":41,"difficulty":14,"q":42,"a":43},"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":45,"difficulty":25,"q":46,"a":47},"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":49,"difficulty":25,"q":50,"a":51},"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":53,"difficulty":25,"q":54,"a":55},"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":57,"difficulty":14,"q":58,"a":59},"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":61,"difficulty":14,"q":62,"a":63},"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":65,"difficulty":66,"q":67,"a":68},"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":70,"difficulty":66,"q":71,"a":72},"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":74,"difficulty":66,"q":75,"a":76},"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":78,"difficulty":66,"q":79,"a":80},"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":82,"difficulty":14,"q":83,"a":84},"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":86,"difficulty":14,"q":87,"a":88},"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":90,"difficulty":14,"q":91,"a":92},"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":94,"difficulty":66,"q":95,"a":96},"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":98,"difficulty":66,"q":99,"a":100},"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":102,"difficulty":14,"q":103,"a":104},"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":106,"difficulty":14,"q":107,"a":108},"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":110,"difficulty":14,"q":111,"a":112},"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":11},"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","Generics","generics","2026-06-20","RZvplRmyNsoceXctYSH0TDs9i3Jrl9pRwiY6A4Jnbjk",[123,124,127],{"subtopic":6,"path":21,"order":20},{"subtopic":125,"path":126,"order":12},"Wildcards & Bounded Types","\u002Fjava\u002Fgenerics\u002Fwildcards-bounds",{"subtopic":128,"path":129,"order":130},"Type Erasure","\u002Fjava\u002Fgenerics\u002Ftype-erasure",3,{"path":132,"title":133},"\u002Fblog\u002Fjava-generics-basics-type-safety","Java Generics — Type Safety, Generic Classes, Methods & the Diamond Operator",1782244116038]