猿问

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

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

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

如果擦除将T类内部替换BoxSomething(类引用),是不是意味着接口:Seralizable,Cloneable必须由 Something 类实现,所以只有我觉得指定Seralizable,Cloneable接口是多余的?此外,如果菱形内仅提及接口,默认情况下是否将其T视为Object参考,会发生什么情况?

我很高兴能提供一个泛型类的示例和一个泛型方法的示例(如果泛型方法中存在多个扩展)。


杨__羊羊
浏览 117回答 1
1回答

函数式编程

您实际上已经回答了您的问题:如果类型不受限制,则擦除是第一个边界或对象。让我们看几个例子:public class A implements Serializable {&nbsp; &nbsp; //&nbsp; since the first bound is Cloneable, the erasure is Cloneable&nbsp; &nbsp; static <T extends Cloneable & Serializable> void doSomething1(T t) {}&nbsp; &nbsp; //&nbsp; since the first bound is Serializable, the erasure is Serializable&nbsp; &nbsp; static <T extends Serializable & Cloneable> void doSomething2(T t) {}&nbsp; &nbsp; // since T is not bounded, the erasure is Object&nbsp; &nbsp; static <T> void doSomething(T t) {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("A");&nbsp; &nbsp; }&nbsp; &nbsp; // the type of A is a class, so it has to come first&nbsp; &nbsp; // the erasure is A since it comes first&nbsp; &nbsp; static <T extends A & Serializable> void doSomething(T t) {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("B");&nbsp; &nbsp; }&nbsp; &nbsp; // not possible because the bounds are two classes&nbsp; &nbsp; // static <T extends Object & A> void doSomething(T t) {return null;}}由于擦除不同,方法可以具有相同的名称!但这是完全不推荐的,而且相当令人困惑,因为行为发生了变化:public static void main(String[] args) {&nbsp; &nbsp; A.doSomething(new Object());&nbsp; // prints "A"&nbsp; &nbsp; A.doSomething(new A());&nbsp; &nbsp; &nbsp; &nbsp;// prints "B"}编辑后回答您的问题:不,这并不多余。指定类型参数需要实现的类型使您可以访问边界的方法。让我们看一下下面的例子:public final class Box<T extends A & Comparable<T>> {&nbsp; &nbsp; private T item1;&nbsp; &nbsp; private T item2;&nbsp; &nbsp; int compare() {&nbsp; &nbsp; &nbsp; &nbsp; // this is the compare method of Comparable interface&nbsp; &nbsp; &nbsp; &nbsp; return item1.compareTo(item2);&nbsp; &nbsp; }}从上面的示例中您可以看到它A没有实现该Comparable接口。这意味着,如果您只是编写,则无法简单地比较使用该方法Box<T extends A>中的两项,因为没有实现。如果您希望框项属于类并实现接口,则需要指定两个边界。BoxcompareToAComparableA ComparableA实现的不是参考Comparable,而是T参考!即使删除了T extends A & Comparable<T>will,A编译器仍然可以在较低级别上执行转换。这就是这里正在发生的事情。如果您使用使用checkcastjavap指令的实用程序检查字节码,您可以看到这一点:&nbsp; int compare();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;....&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0: aload_0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1: getfield&nbsp; &nbsp; &nbsp; #7&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Field item1:LA;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4: checkcast&nbsp; &nbsp; &nbsp;#13&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// class java/lang/Comparable&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7: aload_0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;8: getfield&nbsp; &nbsp; &nbsp; #15&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Field item2:LA;&nbsp; &nbsp; &nbsp; &nbsp; 11: invokeinterface #18,&nbsp; 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I&nbsp; &nbsp; &nbsp; &nbsp; 16: ireturn&nbsp; &nbsp; &nbsp; &nbsp; ....
随时随地看视频慕课网APP

相关分类

Java
我要回答