What is an upper bound on a generic type parameter in Java, and why would you use one?
answer
- extends = type or subtype
- unlocks the bound's methods
- caller must pass a subtype
- default bound is Object
- extends covers interfaces too
basics
~20 sAn upper bound uses the extends keyword to say a type parameter must be a given type or a subtype of it, like <T extends Number>. This lets you call that type's methods inside the class or method.
solid answer
~40 sAn upper bound restricts a type parameter to a particular type or any of its subtypes using the extends keyword, e.g. <T extends Number>. Without a bound, the compiler only knows the parameter is some Object, so you can only call Object's methods on values of that type. By bounding it to Number, the compiler now guarantees every T is a Number, so you can safely call Number methods like intValue() or doubleValue() on a T. The bound is both a constraint (callers must supply Number or a subtype like Integer or Double) and a capability (your code gains access to the bound's members). You use it whenever your generic logic needs to do more than store and return values opaquely.
code
java · 11 linesclass Summer<T extends Number> {
double sum(java.util.List<T> items) {
double total = 0;
for (T item : items) {
total += item.doubleValue(); // legal: T is guaranteed to be a Number
}
return total;
}
}
// Summer<Integer> ok; Summer<Double> ok; Summer<String> -> compile errorgo deeper
Knows extends restricts T to a type or its subtypes and lets you call that type's methods; can read <T extends Number>.
Can explain the constraint-plus-capability duality and that the default bound is Object; writes a correct bounded generic method.
Articulates how the bound is the compile-time contract that unlocks member access, distinguishes it from wildcards, and reasons about API ergonomics.
Frames bounds within overall API design and variance strategy, weighing bounded parameters vs wildcards for library surface and evolution.
## Background: what generics are **Generics** let you write a class or method that works over many types while keeping type safety. You declare a **type parameter** (a placeholder like `T`, `E`, or `N`) in angle brackets. For example, `class Box<T>` means "a Box of some type T decided later." When someone writes `Box<String>`, the compiler substitutes `String` for `T`. ## The problem an upper bound solves With an **unbounded** parameter `<T>`, the compiler knows nothing about `T` except that it is *some* object. So inside the class the only methods you may call on a `T` value are those defined on `java.lang.Object` (`equals`, `hashCode`, `toString`, etc.). If you try `t.doubleValue()` the code won't compile, because not every possible `T` has that method. ## What an upper bound is An **upper bound** narrows the set of allowed types. You write `<T extends Bound>`, which says: *T must be `Bound` or any subtype (more specific type) of `Bound`.* The word **extends** here is reused from inheritance, but in generics it means "is `Bound` or a subtype of `Bound`" and it covers BOTH extending a class AND implementing an interface (you never write `implements` in a bound). Two consequences follow: 1. **Constraint on callers.** `new Calculator<Integer>()` is allowed because `Integer` is a subtype of `Number`; `new Calculator<String>()` is rejected at compile time because `String` is not a `Number`. 2. **Capability inside the code.** Because the compiler now *guarantees* every `T` is at least a `Number`, you may call any `Number` member on a `T` value: `t.intValue()`, `t.doubleValue()`, etc. The bound is the contract that unlocks those calls. ## A concrete example ```java class Summer<T extends Number> { double sum(java.util.List<T> items) { double total = 0; for (T item : items) { total += item.doubleValue(); // legal because T is a Number } return total; } } ``` Here `Summer<Integer>`, `Summer<Double>`, and `Summer<Long>` all work; `Summer<String>` does not compile. ## The default bound is Object When you omit a bound and just write `<T>`, the compiler treats it as if you had written `<T extends Object>`. So *every* type parameter has an upper bound; "unbounded" really means "bounded by Object." That is why an unbounded `T` only offers Object's methods. ## Why it matters Upper bounds are how generic code goes beyond opaque store-and-return containers to actually *operate* on the values it holds, while still being type-safe and reusable across a whole family of related types.
- If you omit the bound and just write <T>, what bound does the compiler assume?It is implicitly <T extends Object>, which is why you can only call Object's methods on an unbounded T.
- Why can't you call doubleValue() on an unbounded T?Because the compiler only knows T is some Object; doubleValue() is a Number method, and not every possible T is a Number, so the call is unsafe and rejected.
saying these in an interview costs you the question
- Thinking extends in a bound means class-inheritance only — it also covers implementing interfaces
- Saying an unbounded <T> has no bound — it is implicitly <T extends Object>
- Believing the bound is only a restriction and forgetting it also grants access to the bound's members