I often find code which uses generics in Java like this:
public static <T extends Object & Interface> foo(T object) {
...
}
Since in Java every class inherites from object class I'm not sure if extends Object
gives a special meaning or is used for special purposes. Can anyone tell me if there is a different background using this or this is implicit given when you take <T extends Interface>
?
super is a lower bound, and extends is an upper bound.
super T denotes an unknown type that is a supertype of T (or T itself; remember that the supertype relation is reflexive). It is the dual of the bounded wildcards we've been using, where we use ? extends T to denote an unknown type that is a subtype of T .
T is meant to be a Type. E is meant to be an Element ( List<E> : a list of Elements) K is Key (in a Map<K,V> ) V is Value (as a return value or mapped value)
In Java there's a single metaclass: Class . Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.
<T extends Object & Interface>
That Object
is clearly redundant and typically equals to
<T extends Interface>
Note that using Interface
as a class name is highly discouraged.
This may be necessary to make your code backwards-compatible on binary level. Suppose that you have the following utility class:
public class Utils {
public static <T> int length(T obj) {
if(obj instanceof CharSequence) {
return ((CharSequence)obj).length();
}
return 0;
}
}
It's published as a library and used in some applications like this:
public class Main {
public static void main(String... args) {
System.out.println(Utils.length("foo"));
}
}
Works fine. However later you decided that it's good to limit your method only to implementations of some interface CharSequence
as for other objects it always returns 0 anyways and seems that nobody uses your method with non-CharSequence parameter. So you change the signature to
public static <T extends CharSequence> int length(T obj) { ... }
Now if you link the Main
class with new version of your library, it will fail with java.lang.NoSuchMethodError
. That's because the erased signature of your method changed. Before it was int length(Object obj)
, but now it's int length(CharSequence obj)
. If you recompile the Main
class, it will work fine, but it's not always possible to recompile all the existing code. Thus the trick could be performed:
public static <T extends Object & CharSequence> int length(T obj) { ... }
Now you're actually limiting the parameter to CharSequence
interface, but the erased signature is back to int length(Object obj)
(the erased type is always the first in the chain of A & B & C & ...
, it's officially documented), so the new version of Utils
class is binary compatible with the old code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With