我经常发现Java中使用泛型的代码如下:
public static <T extends Object & Interface> foo(T object) {
...
}
由于在Java中每个类都继承自对象类,我不确定extends Object
是否具有特殊含义或用于特殊目的。谁能告诉我这是有不同的背景使用它还是这是隐含的当你选择<T extends Interface>
时?
<T extends Object & Interface>
Object
显然是多余的,通常等于
<T extends Interface>
注意,不建议使用Interface
作为类名。
这个可能是使你的代码在二进制级别上向后兼容所必需的。假设您有以下实用程序类:
public class Utils {
public static <T> int length(T obj) {
if(obj instanceof CharSequence) {
return ((CharSequence)obj).length();
}
return 0;
}
}
它作为一个库发布,并在一些应用程序中使用,如:
public class Main {
public static void main(String... args) {
System.out.println(Utils.length("foo"));
}
}
工作好。然而,后来你决定将你的方法限制在一些接口CharSequence
的实现上是很好的,因为其他对象无论如何总是返回0,似乎没有人使用你的非charsequence参数的方法。所以你把签名改成
public static <T extends CharSequence> int length(T obj) { ... }
现在,如果您将Main
类与新版本的库链接,则java.lang.NoSuchMethodError
将失败。这是因为你的方法的 deleted 签名改变了。以前是int length(Object obj)
,现在是int length(CharSequence obj)
。如果您重新编译Main
类,它将正常工作,但是重新编译所有现有代码并不总是可能的。因此,可以执行此技巧:
public static <T extends Object & CharSequence> int length(T obj) { ... }
现在您实际上将参数限制为CharSequence
接口,但擦除的签名又回到了int length(Object obj)
(擦除类型始终是A & B & C & ...
链中的第一个,这是官方文档),因此新版本的Utils
类与旧代码是二进制兼容的。
正如您所指出的,任何T
都会隐式地扩展Object
。显式地定义T extends Object
是完全多余的,您可以(并且可能应该)删除它,并只定义T extends Interface
。