16

我创建了界面TwoMethods。源代码:

interface TwoMethods<T>
{
    public void method(T t);
}

然后我创建了实现这个接口的类,反汇编后我看到了 2 个方法。班级:

class A implements TwoMethods<A>
{
    @Override
    public void method(A a) {}
}

拆机后:

class A implements TwoMethods<A> {
   A();
   public void method(A); //first
   public void method(java.lang.Object); //second
}

接口也是Comparable如此。为什么当我创建参数化接口时我有 2 种方法。总是,当我使用参数时?我还有Object作为参数的方法?

4

2 回答 2

18

method(java.lang.Object)被称为桥接方法,它是由于编译时的类型擦除而生成的。

查看类型擦除和桥接方法的效果

于 2013-12-25T10:51:12.570 回答
15

如果我们查看接口 TwoMethods 字节码,我们将看到实际的方法是

public abstract method(Ljava/lang/Object;)V

也就是说,关于类型参数的字节码级别的信息不存在,类型被删除,JVM 根本不知道泛型,类型参数被替换为Object或如果T extends X替换为X。所以从JVM的角度来看

class A implements TwoMethods<A> {
    public void method(A a) {
        ...

method(A a)不覆盖接口方法,因为在字节码中它method(Object obj)可以覆盖它。为了解决这个问题,编译器在 A 类中构建了一个隐式方法,即所谓的桥接方法

public void method(Object obj) {
     method((A)obj);
}

仅在字节码中可见。现在这个代码

A a = new A();
TwoMethods<A> tm = a;
tm.method(a);

编译器将替换tm.method(a)为对桥的调用

   INVOKEINTERFACE test/TwoMethods.method(Ljava/lang/Object;)V

这会将呼叫重定向到A.method(A a);

于 2013-12-25T11:14:50.660 回答