Java Generics:特殊用法 <T 扩展了对象和接口>



我经常发现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

最新更新