skip to content

In a multiple-bound declaration, what are the rules about including a class bound versus interface bounds, and their ordering?

level: middleimportance: must knowfreq 48%

answer

  1. At most one class bound
  2. Class bound must be first (leftmost)
  3. Interfaces follow the class
  4. Two classes = compile error
  5. Leftmost bound = the erasure

basics

~20 s

You may have at most one class in the bounds, and if there is one it must come first. All the other bounds must be interfaces, and they go after the class. Multiple classes are not allowed.

solid answer

~50 s

In `<T extends A & B & C>` at most one of the bounds may be a class; all the rest must be interfaces. This follows from single inheritance: a type can extend only one class, so requiring two distinct classes could be unsatisfiable, and Java forbids it outright. When a class bound is present it must be listed **first**, before any interface bounds; otherwise the compiler reports an error like 'interface expected here.' If all bounds are interfaces, order does not matter semantically (though a stable convention helps readability). A practical reason for the class-first rule is type erasure: the leftmost bound is the one a generic type parameter erases to, so the compiler wants the (usually richer) class type in that position. So `<T extends Number & Comparable<T> & Serializable>` is legal, but putting `Number` after an interface is a compile error.

go deeper

for a junior

Knows there can be at most one class bound and that, if present, the class comes first; can spot that two classes is illegal.

for a middle

States all three rules precisely and predicts the compiler errors ('interface expected' / two-class), tying the single-class rule to single inheritance.

for a senior

Explains class-first via type erasure (leftmost bound becomes the erasure) and why that yields better bytecode and method access.

for a principal

Discusses how the erasure-of-leftmost-bound rule interacts with library/API design, binary compatibility of changing bound order, and bridge-method generation.

## Background you need first In Java, every reference type is either a **class** (e.g. `Number`, `String`, your own `class Foo`) or an **interface** (e.g. `Comparable`, `Serializable`). A class can **extend at most one** other class (Java has *single class inheritance*) but can **implement many** interfaces. A **bounded type parameter** `<T extends ...>` constrains what T may be; **multiple bounds** join several constraints with `&` (see the syntax question). ## Rule 1 — at most one class bound Because a concrete type can have only one superclass chain, you cannot meaningfully require it to extend two *unrelated* classes at once. Java therefore forbids more than one **class** among the bounds: ```java <T extends Number & String> // ERROR: String and Number are both classes ``` You may, however, have **zero** class bounds (all interfaces) or **exactly one**. ## Rule 2 — the class bound must come first If you include a class among the bounds, it must be the **leftmost** bound; every bound after it must be an interface: ```java <T extends Number & Comparable<T> & Serializable> // OK: class first, then interfaces <T extends Comparable<T> & Number> // ERROR: 'interface expected' — class not first ``` The compiler error typically reads *"interface expected here"*: once it has parsed an interface bound, it will not accept a class in a later position. ## Rule 3 — interface-only bounds have no ordering constraint When *all* bounds are interfaces, any order compiles: ```java <T extends Comparable<T> & Serializable> // same as <T extends Serializable & Comparable<T>> // both legal ``` A team may still adopt a fixed convention for consistency, but it is not enforced. ## Why class-first? The erasure reason **Type erasure** is how Java implements generics: at compile time the generic type information is removed and each type parameter is replaced by the **erasure of its leftmost bound** (or `Object` if unbounded). So for `<T extends Number & Comparable<T>>`, T erases to `Number`. Putting the class first means the compiler can pick the most specific *class* as the erasure, which produces better bytecode (fewer casts, the class's methods are directly callable). If interfaces could precede the class, the leftmost-bound rule would erase to an interface and lose the class typing. The ordering rule keeps erasure predictable and useful. (You can sometimes nudge the chosen erasure by reordering interface bounds, but the class, when present, is always leftmost.) ## Worked legal/illegal table | Declaration | Legal? | Why | |---|---|---| | `<T extends Number & Comparable<T>>` | ✅ | one class first, then interface | | `<T extends Comparable<T> & Serializable>` | ✅ | all interfaces, order free | | `<T extends Comparable<T> & Number>` | ❌ | class after an interface | | `<T extends Number & String>` | ❌ | two class bounds | | `<T extends Serializable & Comparable<T> & Cloneable>` | ✅ | three interfaces | ## First-principles summary Single class inheritance ⇒ at most one class bound. Erasure picks the leftmost bound ⇒ the class, when present, must be first so it becomes the erasure. Everything after the class is an interface; interface-only bounds may be in any order.

  • Why is the class required to be the first bound specifically?
    Type erasure replaces T with the erasure of its leftmost bound. Forcing the class first makes the (more specific) class the erasure, yielding better bytecode and direct access to its methods; an interface in front would erase to the interface instead.
  • Is <T extends Number & String> rejected because of ordering or for another reason?
    For another reason: Number and String are both classes, and a type can extend only one class. It is a 'two class bounds' error, independent of order.

saying these in an interview costs you the question

  • Claiming you can list two classes as bounds — single inheritance forbids it.
  • Putting the class after an interface and expecting it to compile — it gives 'interface expected'.
  • Thinking interface order is enforced — only the class-first rule is mandatory; interface-only order is free.

context