实现通用java接口添加了额外的方法

时间:2017-06-26 13:29:52

标签: java generics inheritance

我有一个通用的java接口Id<T>,其中包含一个方法T getId()和一个实现MyClass的类Id<Long>。当我使用java反射检查MyClass上声明的方法时,我看到两个方法:一个返回类型为Long,另一个返回类型为Object。第二种方法来自何处以及如何将其删除?

以下是来源:

package mypackage;

import java.lang.reflect.Method;

public class MainClass {
    public static void main(String[] args) {
        for (Method method : MyClass.class.getDeclaredMethods()) {
            System.out.println(method);
        }
        // prints out two lines
        // public java.lang.Long mypackage.MyClass.getId()   <-- ok
        // public java.lang.Object mypackage.MyClass.getId() <-- not ok
    }
}

interface Id<T> {
    T getId();
}

class MyClass implements Id<Long> {
    @Override
    public Long getId() {
        return new Long(0);
    };
}

3 个答案:

答案 0 :(得分:3)

第二种方法是synthetic bridge方法,您可以使用method.isSynthetic()method.isBridge()进行检查。您无法删除它,但如果您不想在声明的方法列表中看到它,只需检查所有这些方法isBridge() == false

在编译期间,合成桥方法会自动添加到泛型类中。您可以阅读有关合成方法here的更多信息。

for (Method method : MyClass.class.getDeclaredMethods()) {
    System.out.println("Method: " + method);
    System.out.println("synthetic: " + method.isSynthetic());
    System.out.println("bridge: " + method.isBridge());
}

// 1
//Method: public java.lang.Long Main$MyClass.getId()
//synthetic: false
//bridge: false
// 2
//Method: public java.lang.Object Main$MyClass.getId()
//synthetic: true
//bridge: true

答案 1 :(得分:2)

这是功能。

中提出了同样的问题

JDK-8060179 Class.getDeclaredMethods() returning inconsistent results with generics并以'不是错误'结束。

答案 2 :(得分:1)

您可以通过javap -c MyClass找到已编译的方法:

Compiled from "Test.java"
class MyClass implements Id<java.lang.Long> {
  MyClass();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public java.lang.Long getId();
    Code:
       0: new           #2                  // class java/lang/Long
       3: dup
       4: lconst_0
       5: invokespecial #3                  // Method java/lang/Long."<init>":(J)V
       8: areturn

  public java.lang.Object getId();
    Code:
       0: aload_0
       1: invokevirtual #4                  // Method getId:()Ljava/lang/Long;
       4: areturn
}

正如您所看到getId 2 方法,一个返回类型 Longimplementation而另一个<{1}} 返回类型Object类型(它正在调用Long getId方法)。

返回类型 Object 方法用于在未指定泛型类型并桥接到Long getId时进行处理方法。例如:

    Id<Long> id = new Id<Long>() {
        @Override
        public Long getId() {
            return null;
        }
    };
    Long id1 = id.getId();

如上面的代码段,我们可以使用Id类型实现Long匿名类。但问题是我们也可以实现Id匿名类,而不在变量中指定泛型类型

    Id id = new Id<Long>() {
        @Override
        public Long getId() {
            return null;
        }
    };
    Object id1 = id.getId();

所以现在编译器无法推断变量id泛型类型,当id.getId()它返回类型Object类型时变量,表示它调用此方法public java.lang.Object getId();并桥接到public java.lang.Long getId();方法。