skip to content

How do you give a type parameter multiple upper bounds, and what rules govern the order and number of class versus interface bounds?

level: middleimportance: should knowfreq 40%

answer

  1. join bounds with &
  2. at most one class bound
  3. class bound goes first
  4. & vs comma (comma = separate params)
  5. erasure uses the first bound

basics

~20 s

Combine bounds with the & symbol, like <T extends Number & Comparable<T>>. T must satisfy all of them. You can list at most one class, and it must come first; the rest must be interfaces.

solid answer

~50 s

Java lets a type parameter have several upper bounds joined by &, e.g. <T extends Number & Comparable<T> & Serializable>. The substituted type must satisfy every bound simultaneously, and inside the code you may call members from all of them. The rules: at most one of the bounds may be a class (the others must be interfaces), and if a class bound is present it must be listed first. This restriction exists because Java has single class inheritance — a type can extend only one class but implement many interfaces, so allowing two class bounds would be unsatisfiable. The compiler also uses the first bound as the erasure of the type parameter, which can matter for binary compatibility and bridge methods. Multiple bounds are useful when your algorithm needs capabilities from more than one type, such as numeric operations plus comparability.

code

java · 6 lines
java
static <T extends Number & Comparable<T>> T clamp(T value, T low, T high) {
    if (value.compareTo(low) < 0)  return low;   // from Comparable
    if (value.compareTo(high) > 0) return high;  // from Comparable
    return value;                                // could also use value.doubleValue() from Number
}
// clamp(5, 0, 10) -> 5 ; clamp(15, 0, 10) -> 10

go deeper

for a junior

Recognizes the & syntax for multiple bounds and that all bounds must be satisfied.

for a middle

States the one-class-and-first rule and explains it via single class inheritance; writes a correct multi-bounded method.

for a senior

Explains erasure picking the leftmost bound and the resulting impact on signatures and bridge methods.

for a principal

Considers binary-compatibility and API-evolution effects of bound ordering and erasure when designing library generics.

## Recap: a single upper bound `<T extends Number>` restricts `T` to `Number` or a subtype and lets you call `Number` members on a `T`. Sometimes one bound is not enough — your code may need `T` to be *both* numeric *and* comparable, for instance. ## Syntax for multiple bounds: the & operator You join several bounds with the ampersand `&`: ```java <T extends Number & Comparable<T> & java.io.Serializable> ``` This reads: *T must be a Number, AND implement Comparable<T>, AND implement Serializable.* The substituted type must satisfy **all** of them at once, and within the generic code you may invoke members from **every** listed bound. Note it is `&`, not a comma — a comma separates different type parameters (`<A, B>`), while `&` combines multiple bounds on a single parameter. ## Rule 1: at most one class bound Among the bounds, **no more than one may be a class**; the rest must be **interfaces**. The reason is Java's **single inheritance of classes**: a concrete type can `extend` only one class but `implement` any number of interfaces. If two unrelated classes were allowed as bounds, no type could ever satisfy both, so the restriction is enforced at compile time. ## Rule 2: the class bound must come first If one of the bounds is a class, it must be the **first** bound in the list. So `<T extends Number & Comparable<T>>` is legal, but `<T extends Comparable<T> & Number>` is a compile error. Interface-only bound lists have no ordering requirement among themselves. ## Rule 3: erasure uses the first bound At compile time generics are **erased** — type parameters are replaced by their bound in the bytecode. For a multiply-bounded parameter, erasure uses the **leftmost** bound. So `<T extends Number & Comparable<T>>` erases `T` to `Number`. This is one practical reason the class bound (if any) goes first: it generally makes the erased signature the most useful, and it affects generated bridge methods and binary compatibility. ## A worked example ```java static <T extends Number & Comparable<T>> T clamp(T value, T low, T high) { if (value.compareTo(low) < 0) return low; // compareTo from Comparable if (value.compareTo(high) > 0) return high; return value; } // could also call value.doubleValue() here, from Number ``` Here `clamp` needs `compareTo` (from `Comparable`) and could also use numeric methods (from `Number`). A type like `Integer` satisfies both bounds, so `clamp(5, 0, 10)` compiles. ## When to reach for multiple bounds Use them when a single bound cannot express all the capabilities your generic algorithm requires. Keep the list short; long bound lists are a sign the abstraction may be doing too much.

  • Why can a type parameter have at most one class among its bounds?
    Because Java supports single class inheritance — a type extends only one class — so two class bounds could never be satisfied simultaneously, while many interfaces can be implemented.
  • In <T extends Number & Comparable<T>>, what does T erase to?
    To Number, the leftmost (first) bound, since erasure replaces the type parameter with its first bound.

saying these in an interview costs you the question

  • Using a comma instead of & to combine bounds on one parameter
  • Listing two classes as bounds (only one class is allowed)
  • Putting the class bound after an interface bound
  • Forgetting that erasure picks the leftmost bound

context