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.