为了账号安全,请及时绑定邮箱和手机立即绑定

泛型的擦除如何“替换”多个边界

泛型的擦除如何“替换”多个边界

杨__羊羊 2023-12-13 15:06:37
我读到,在类型擦除过程中,Java 编译器会擦除所有类型参数,如果类型参数有界,则用其第一个界限替换每个参数,如果类型参数无界,则用 Object 替换。但是,我无法理解,指定类型参数需要实现的接口不是多余的吗?例如:public class Box<T extends Something,Seralizable,Cloneable>如果擦除将T类内部替换Box为Something(类引用),是不是意味着接口:Seralizable,Cloneable必须由 Something 类实现,所以只有我觉得指定Seralizable,Cloneable接口是多余的?此外,如果菱形内仅提及接口,默认情况下是否将其T视为Object参考,会发生什么情况?我很高兴能提供一个泛型类的示例和一个泛型方法的示例(如果泛型方法中存在多个扩展)。
查看完整描述

1 回答

?
函数式编程

TA贡献1807条经验 获得超9个赞

您实际上已经回答了您的问题:如果类型不受限制,则擦除是第一个边界或对象。让我们看几个例子:


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>中的两项,因为没有实现。如果您希望框项属于类并实现接口,则需要指定两个边界。BoxcompareToAComparableA Comparable


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


  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

        ....


查看完整回答
反对 回复 2023-12-13
  • 1 回答
  • 0 关注
  • 115 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信