When a type parameter is declared without an explicit bound (just <T>), what is its bound, and what does that imply for the methods you can call?
answer
- <T> equals <T extends Object>
- Object = root supertype
- only Object methods available
- tighten bound to gain methods
- no such thing as truly unbounded
basics
~10 sWriting <T> is the same as writing <T extends Object>. Because T is only known to be an Object, you can call only Object's methods on it, like equals, hashCode, and toString.
solid answer
~40 sAn omitted bound is not the absence of a bound: <T> is implicitly <T extends Object>. Object is the universal supertype of every reference type, so this is the loosest possible upper bound. The practical implication is that the compiler knows nothing about T beyond it being an Object, so the only members it will let you invoke on a T value are those declared on java.lang.Object: equals, hashCode, toString, getClass, and the wait/notify family. You cannot call domain-specific methods like compareTo or doubleValue because not every possible T has them. To gain those, you must tighten the bound, e.g. <T extends Comparable<T>> or <T extends Number>. This is why understanding the implicit Object bound clarifies exactly why bounded parameters are needed.
code
java · 10 linesclass Printer<T> { // implicitly <T extends Object>
void print(T value) {
System.out.println(value.toString()); // ok: toString is on Object
// value.length(); // compile error: not on Object
}
}
class Maxer<T extends Comparable<T>> {
T max(T a, T b) { return a.compareTo(b) >= 0 ? a : b; } // bound grants compareTo
}go deeper
Knows <T> implicitly extends Object and so only Object's methods are callable on a T.
Lists the specific Object methods available and shows how tightening the bound adds capabilities.
Connects the Object default to API design choices about whether a generic should inspect or merely store its values.
Uses the Object-default insight when designing minimal yet capable generic contracts and reasoning about erasure-driven dispatch.
## Setting the stage A **type parameter** is a placeholder for a type, written in angle brackets like `<T>`. The compiler erases generics at runtime but enforces them at compile time; to do that, it must know what operations are valid on a `T`. ## Every type parameter has an upper bound It is a common misconception that `<T>` means "T has no bound." In fact the Java Language Specification treats a missing bound as the bound **`Object`**. So these two declarations are identical: ```java class Box<T> {} class Box<T extends Object> {} ``` `Object` (`java.lang.Object`) is the root of the class hierarchy: every reference type ultimately extends it. Therefore bounding by `Object` allows *any* reference type to be substituted for `T` — the widest possible set. ## What you can do with an Object-bounded T Because the compiler only guarantees that a `T` value is an `Object`, the **only** instance methods it will permit on a `T` are the ones declared on `Object`: - `equals(Object)` - `hashCode()` - `toString()` - `getClass()` - `wait(...)`, `notify()`, `notifyAll()` (from Object's monitor methods) Attempting `t.compareTo(other)` or `t.length()` will not compile, because those members are not on `Object` and not every conceivable `T` would have them. ## Example of the limitation and the fix ```java class Printer<T> { void print(T value) { System.out.println(value.toString()); // ok: toString is on Object // System.out.println(value.length()); // NOT ok: length() is not on Object } } class Maxer<T extends Comparable<T>> { T max(T a, T b) { return a.compareTo(b) >= 0 ? a : b; // ok: bound grants compareTo } } ``` `Maxer` tightens the bound to `Comparable<T>`, so the compiler now guarantees a `compareTo` method exists. ## Why this matters Knowing that the default bound is `Object` explains the *whole point* of upper bounds: you tighten the ceiling from `Object` to something more capable so the compiler will let you call richer methods, while still accepting a family of subtypes. Unbounded generics are best for pure containers that only store and hand back values without inspecting them.
- Name three methods you can legally call on an unbounded T.Any Object method: equals, hashCode, toString (also getClass and the wait/notify family).
- How do you change the declaration so you can call compareTo on a T?Bound it to Comparable, e.g. <T extends Comparable<T>>, which guarantees a compareTo method exists.
saying these in an interview costs you the question
- Saying <T> has no upper bound — it has Object
- Assuming you can call compareTo or domain methods on an unbounded T
- Confusing the implicit Object bound with the raw type (a separate concept)