如何擦除仿制药?多重界限 [英] How erasure of generics "replace" multiple bounds

查看:64
本文介绍了如何擦除仿制药?多重界限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读到,在类型擦除过程中,Java编译器将擦除所有类型参数,如果类型参数是有界的,则将每个参数替换为其第一个边界;如果类型参数是无界的,则将其替换为对象. 但是,我不明白,指定类型参数需要实现的接口不是多余的.例如:

I read that during the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded. But, i can't understand, isn't it redundant to specify the interface that the type parameter needs to implement. For example:

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

如果用Something(类引用)将Box内的T替换为T,那不是说接口:Seralizable,Cloneable必须由Something类实现,所以只有我自己指定Seralizable,Cloneable接口?此外,如果仅在菱形框内提及接口,会发生什么情况,默认情况下T是否会视为 Object 引用?

If erasure replaces T inside the class Box with Something (Class reference), doesn't it mean interfaces: Seralizable,Cloneable must be implemented by Something class, so only me it's feel redundant to specify Seralizable,Cloneable interfaces? In addition what happens if only interfaces are mentioned inside the diamonds, does by default T consider as Object reference?

对于一个泛型类的示例和一个泛型方法的示例(如果泛型方法中存在多个扩展),我将感到高兴.

I will be glad for one example for Generic Class and one example for Generic Method (if multiple extends exist in generics method).

推荐答案

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

You acutally already answered your question: The erasure is the first bound or Object if the type is not bounded. Let's look at a few examples:

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;}
}

由于擦除操作不同,因此方法可以使用相同的名称!但这是完全不推荐的,因为行为会发生变化,这很令人困惑:

Since the erasures are different, the methods can have the same name! But this is totally not recommended and rather confusing because the behavior changes:

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

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

To answer your question after your edit: No, it is not redundant. Specifying the type the type parameter needs to implement gives you access to the methods of the bounds. Let's have a look at the following example:

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>,就不能仅使用A不实现Comparable的方式,就无法使用compareTo方法比较Box中的两项.如果要使框项目属于A 类以实现Comparable接口,则需要指定两个边界.

From the example above you see that A doesn't implement the Comparable interface. That means that if you just write Box<T extends A> you can't compare the two items in your Box using the compareTo method simply because A doesn't implement Comparable. If you want your box items to be of class A and to implement the Comparable interface, you need to specify both bounds.

不是实现ComparableA参考,而是实现T的参考!即使T extends A & Comparable<T>的擦除将是A,编译器仍然可以在较低级别上执行强制转换.这就是这里正在发生的事情.如果使用javap实用程序检查字节码,则可以看到此内容,其中

It's not the A reference that implements Comparable but the T reference! Even though the erasure of T extends A & Comparable<T> will be A the compiler can still perform the cast on a lower level. And this is what's happening here. You can see this, if you inspect the byte code using the javap utility where a checkcast instruction is used:

  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
        ....

这篇关于如何擦除仿制药?多重界限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆