What is a generic method, how is it different from a method in a generic class, and why prefer one over casting?
answer
- <T> goes right before the return type
- Method param is fresh & method-scoped (vs class's param)
- Non-generic class CAN have generic methods (Collections.emptyList)
- Type args are inferred; explicit witness Collections.<String>emptyList()
- Captures input<->output type link -> no casts, no CCE
basics
~20 sA generic method declares its own type parameter (in angle brackets before the return type), so it works for many types while staying type-safe. It's better than casting because the compiler checks the types for you and you write no casts.
solid answer
~40 sA generic method introduces its *own* type parameter, written in angle brackets just before the return type: `static <T> T firstOf(List<T> list)`. That parameter is scoped to the single method, so even a non-generic class can have generic methods (e.g. `Collections.emptyList()`). It differs from a method in a generic class, which reuses the *class's* type parameter. The win over casting is that the type relationship is captured in the signature: the compiler enforces that inputs and outputs line up and you write zero casts, so there's no risk of a ClassCastException. Type arguments are usually **inferred** from the call, so you rarely spell them out; when needed you can supply an explicit witness like `Collections.<String>emptyList()`. Generic methods also enable the static factory idiom that erased boilerplate before the diamond operator.
code
java · 19 lines// Generic method in a NON-generic class
public final class Lists {
private Lists() {}
// <T> declared before the return type
public static <T> T firstOf(List<T> list) {
return list.get(0);
}
// bounded type parameter: T must be Comparable
public static <T extends Comparable<T>> T max(List<T> list) {
T best = list.get(0);
for (T t : list) if (t.compareTo(best) > 0) best = t;
return best;
}
}
String s = Lists.firstOf(List.of("a", "b")); // T inferred = String, no cast
int m = Lists.max(List.of(3, 7, 2)); // T inferred = Integergo deeper
Recognize the <T> before the return type and know a generic method avoids casts by letting the compiler track the type.
Write a generic method, distinguish it from a method that reuses the class's type parameter, and rely on type inference at call sites.
Use bounded type parameters, supply explicit type witnesses when inference fails, and design generic static factories that remove caller casts.
Decide where to expose method-level generics vs class-level generics in an API, weigh inference limits and readability, and set conventions that keep public signatures self-documenting and cast-free.
## Starting point: why type parameters at all Generics let you write code once that works for many types **without giving up type safety**. A **type parameter** is a placeholder type (conventionally a single uppercase letter: `T`, `E`, `K`, `V`) that the caller fills in. A **generic method** is a method that declares its own type parameter. ## Anatomy of a generic method The type parameter list goes in angle brackets **immediately before the return type**: ```java static <T> T firstOf(List<T> list) { return list.get(0); } ``` Here `<T>` declares the parameter; it then appears in the parameter type (`List<T>`) and the return type (`T`). Calling `firstOf(List.of("a","b"))` returns a `String`, and `firstOf(List.of(1,2))` returns an `Integer` — **the same method, fully type-checked for both**. ## Generic method vs method in a generic class These are easy to confuse: - A **method in a generic class** reuses the *class's* type parameter. In `class Box<T> { T get() {...} }`, `get` uses `T` from the class — it isn't itself generic. - A **generic method** declares a *fresh* type parameter that belongs to the method alone. It can live in a non-generic class. `Collections` is not generic, yet `Collections.<T>emptyList()` and `Collections.<T>sort(...)` are generic methods. A class can have both: the class parameter for instance state, plus extra per-method parameters for operations that need their own type. ## Type inference You almost never write the type argument explicitly. The compiler **infers** it from the arguments (and sometimes the target type of an assignment). `firstOf(stringList)` infers `T = String`. When inference can't figure it out — typically a no-arg generic method whose result type isn't constrained by an argument — you supply an **explicit type witness**: `Collections.<String>emptyList()`. Before the diamond operator (`<>`, Java 7), generic static factory methods were the main way to avoid repeating long type arguments. ## Why prefer a generic method over casting Consider a non-generic helper: ```java static Object first(List list) { return list.get(0); } String s = (String) first(names); // unchecked cast; can throw at runtime ``` The caller must cast, and nothing verifies the cast is correct — a wrong type fails at runtime with a ClassCastException. The generic version threads the type through the signature: the compiler proves `first(names)` is a `String`, so **no cast and no runtime surprise**. The type relationship between input and output is *expressed in the API* rather than reconstructed by hope. ## Bounded type parameters A type parameter can be **bounded** with `extends` to require capabilities: `<T extends Comparable<T>> T max(List<T> list)` requires the elements be comparable so the body can call `compareTo`. The bound is checked at compile time. (Bounds on *method* type parameters differ from **wildcards** on parameter *types* — the latter are about flexible APIs and are covered by PECS.) ## The takeaway Reach for a generic method whenever a method's input and output types are related but you want it to work for many types. It captures the relationship in the signature, lets inference remove ceremony at the call site, and eliminates the casts that raw/`Object`-based code forces on callers.
- When do you have to write the type argument explicitly?When the compiler can't infer it — typically a no-argument generic method whose result type isn't fixed by an argument or by the assignment target. Then you give an explicit type witness, e.g. `Collections.<String>emptyList()` or `this.<Integer>method(...)`.
- Can a generic method override or interact with a class's own type parameter?Yes — a method in a generic class can declare its own extra type parameter alongside the class's. The method parameter shadows/adds to the class one; they are independent placeholders. Naming them differently (class `T`, method `U`) keeps it readable.
saying these in an interview costs you the question
- Putting <T> after the return type or omitting it — the declaration must come before the return type.
- Claiming only generic classes can have generic methods — Collections (non-generic) is full of them.
- Confusing a method that merely uses the class's T with a true generic method that declares its own.
- Saying you must always spell out the type argument — inference handles almost all calls.