If you were to complete the generic declaration, then what you would have is a upper-bounded generic type.
public class Foo<T extends Integer> { }
Here, T
is bound to be anything that either is or extends from an Integer
. But, since Integer
is a final
class...it'd only be able to hold Integer
.
So, a declaration like these are compile-time legal and enforced:
Foo<Integer> foo = new Foo<>();
Foo bar = new Foo(); // This will produce raw type warnings!
...whereas a declaration like this isn't compile-time legal, since the bound is that it must either be or extend Integer
.
Foo<Long> baz = new Foo<>();
Formally, the compiler will show you this:
Error:(17, 56) java: cannot infer type arguments for Foo<>; reason: no instance(s) of type variable(s) T exist so that Foo<T> conforms to Foo<java.lang.Long>
If you went higher in Integer
's hierarchy, you'd arrive at Number
, which would allow you to instantiate with any class that extended Number
:
public class Foo<T extends Number> { }
Then, the Long
generic type would be legal, and your permissible types would be these:
Number
Short
Integer
Double
Float
Byte
BigDecimal
BigInteger
...just to name a few.