如何擦除泛型 "replace" 多个边界

How erasure of generics "replace" multiple bounds

我读到,在类型擦除过程中,Java 编译器擦除所有类型参数,如果类型参数是有界的,则用第一个边界替换每个参数,如果类型参数是无界的,则用 Object 替换。 但是,我无法理解,指定类型参数需要实现的接口是不是多余的。例如:

public class Box<T extends Something,Seralizable,Cloneable>

如果erasure把classBox里面的T替换成Something(Class引用),那不就意味着interfaces:Seralizable,Cloneable 必须由 Something class 实现,所以只有我觉得指定 Seralizable,Cloneable 接口是多余的?此外,如果在菱形中仅提及接口会发生什么,默认情况下 T 是否视为 Object 参考?

我很乐意为泛型 Class 提供一个示例,为泛型方法提供一个示例(如果泛型方法中存在多个扩展)。

你实际上已经回答了你的问题:擦除是第一个边界或对象,如果类型没有边界的话。让我们看几个例子:

public class A implements Serializable {
    //  since the first bound is Cloneable, the erasure is Cloneable
    static <T extends Cloneable & Serializable> void doSomething1(T t) {}

    //  since the first bound is Serializable, the erasure is Serializable
    static <T extends Serializable & Cloneable> void doSomething2(T t) {}

    // since T is not bounded, the erasure is Object
    static <T> void doSomething(T t) {
        System.out.println("A");
    }

    // the type of A is a class, so it has to come first
    // the erasure is A since it comes first
    static <T extends A & Serializable> void doSomething(T t) {
        System.out.println("B");
    }

    // not possible because the bounds are two classes
    // static <T extends Object & A> void doSomething(T t) {return null;}
}

由于擦除不同,方法可以有相同的名称!但是完全不推荐这样做,因为行为改变而相当混乱:

public static void main(String[] args) {
    A.doSomething(new Object());  // prints "A"
    A.doSomething(new A());       // prints "B"
}

编辑后回答您的问题:不,这不是多余的。指定类型参数需要实现的类型可以让您访问边界的方法。让我们看看下面的例子:

public final class Box<T extends A & Comparable<T>> {
    private T item1;
    private T item2;

    int compare() {
        // this is the compare method of Comparable interface
        return item1.compareTo(item2);
    }
}

从上面的示例中,您可以看到 A 没有实现 Comparable 接口。这意味着如果你只是写 Box<T extends A> 你不能使用 compareTo 方法比较 Box 中的两个项目,因为 A 没有实现 Comparable.如果你想让你的box item是class A 来实现Comparable接口,你需要指定这两个bounds.

实现Comparable的不是A引用,而是T引用!即使 T extends A & Comparable<T> 的擦除将是 A,编译器仍然可以在较低级别执行转换。这就是这里发生的事情。如果您使用 javap 实用程序检查字节码,其中使用了 checkcast 指令,您可以看到这一点:

  int compare();
         ....
         0: aload_0
         1: getfield      #7                  // Field item1:LA;
         4: checkcast     #13                 // class java/lang/Comparable
         7: aload_0
         8: getfield      #15                 // Field item2:LA;
        11: invokeinterface #18,  2           // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
        16: ireturn
        ....