What is a generic constructor, and how are its type parameters independent of the enclosing class's?
answer
- `<E>` before the constructor name
- Constructor type params ≠ class type params (separate scopes)
- Non-generic class can have a generic constructor
- Generic class can add extra constructor type params
- Witness syntax: `new <Type>ClassName(...)` (rare)
basics
~20 sA constructor can declare its own type parameters in angle brackets before the constructor name, separate from the class's type parameters. So even a class that isn't generic can have a constructor that takes a generic argument.
solid answer
~50 sA generic constructor declares a type-parameter section before the constructor name — `<E> MyClass(E arg)` — just as a generic method does before its return type. These type parameters are **scoped to the constructor only** and are completely independent of any type parameters on the class. A non-generic class can therefore have a generic constructor, and a generic class `Box<T>` can have a constructor that introduces an *additional* parameter `E` unrelated to `T`. At the `new` call the compiler infers the constructor's type arguments from the arguments passed; you can also supply a witness, though the syntax (`new <String>Box(...)`) is unusual and rarely seen. The practical use is letting a constructor accept and process an argument of a type it doesn't need to remember as state — e.g. computing a field from a generically-typed input without making the whole class generic over that type.
code
java · 10 linesclass Holder { // non-generic class
private final String value;
<E> Holder(E source) { // generic constructor, owns E
this.value = source.toString();
}
}
Holder h = new Holder(42); // E inferred as Integer
// rare explicit witness:
Holder h2 = new <Integer>Holder(42);go deeper
Aware that constructors can take generically-typed arguments, even if rarely.
Can write a generic constructor and explain its <E> placement before the constructor name.
Articulates the independence of constructor vs class type parameters and when keeping genericity local avoids leaking a type into the class signature.
Weighs generic constructor vs generic class vs static factory in API design; understands the rarity and readability trade-offs of constructor witnesses.
## Recap: two places type parameters can live A type parameter (a placeholder like `T` or `E`) can be declared on a **class** (`class Box<T>`) or on a **method** (`<T> T m(...)`). There is a third, less-known place: a **constructor**. ## What a generic constructor is A **generic constructor** declares its own type-parameter section, placed in angle brackets **immediately before the constructor name** (which is the class name): ```java class Holder { // NOT a generic class private final String value; <E> Holder(E source) { // generic constructor: owns E this.value = source.toString(); } } ``` Here `E` belongs only to the constructor. It exists for the duration of constructing the object and is used to type the constructor's parameter; it is *not* stored as the object's type. ## Independence from the class's type parameters This is the key point interviewers probe. The constructor's type parameters and the class's type parameters are **separate scopes**: - A **non-generic class** (like `Holder` above) can have a generic constructor. The class has no `<...>`, yet the constructor introduces `E`. - A **generic class** can have a constructor that adds *more* type parameters beyond the class's own, and they need not relate: ```java class Box<T> { private final T item; <E extends Number> Box(T item, E hint) { // T from class, E from constructor this.item = item; // use hint as a Number, e.g. hint.intValue() } } ``` Here `T` is the class's parameter (it determines `Box<String>` vs `Box<Integer>`), while `E` is the constructor's own, used only while building the object. ## How the type argument is chosen Just like generic methods, the constructor's type argument is **inferred** from the arguments at the `new` expression: ```java new Holder(42); // E inferred as Integer new Box<>("hi", 3.0); // T = String (diamond/explicit), E = Double (inferred) ``` Note the `Box` example has *two* inference sources: the class type parameter `T` (from the diamond `<>` or an explicit `Box<String>`) and the constructor type parameter `E` (from the second argument). ## Explicit type witness on a constructor You *can* supply an explicit witness for the constructor's parameters, with an unusual syntax — the angle brackets go **after `new` and before the class name**: ```java new <Integer>Holder(42); ``` This is legal but almost never written in real code; inference virtually always suffices, and the diamond `<>` handles the *class* type parameters separately. ## Why and when to use one The practical motivation: a constructor sometimes needs to accept an argument of an arbitrary type to *compute* or *derive* something, without the class having to be generic over that type. Making the whole class generic just to type one constructor argument would leak that type into every usage of the class. A generic constructor keeps that genericity local to construction. ## Mental model A generic constructor is 'a generic method whose return is the new object.' Its `<...>` sits before the (constructor) name, it infers its types from the arguments, and it lives in a scope wholly separate from the class's own type parameters.
- Can a non-generic class have a generic constructor?Yes. The constructor declares its own type parameter (`<E> ClassName(E arg)`), independent of the class. The class signature stays non-generic.
- How is a constructor's type argument supplied explicitly?With a witness after `new` and before the class name: `new <Integer>Holder(42)`. This is legal but rarely used; inference normally handles it. The diamond `<>` handles the class's type parameters, which is a separate concern.
saying these in an interview costs you the question
- Believing a class must be generic to have a generic constructor
- Confusing the constructor's `<E>` with the class's `<T>`
- Putting the constructor witness in the wrong place (it goes after `new`, before the class name)
- Thinking the constructor's type parameter becomes part of the object's type