Python中文网

一个关于 编程问题的解答网站.

有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我有一个通用java接口Id<T>,其中有一个方法T getId(),还有一个实现Id<Long>的类MyClass。当我使用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) 个答案

  1. # 1 楼答案

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

    在编译过程中,合成桥方法会自动添加到泛型类中。你可以阅读更多关于合成方法的内容

    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
    
  2. # 3 楼答案

    您可以通过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
    }
    

    正如你所看到的,getId2个方法,一个返回类型是Long作为implementation,另一个返回类型是Object类型(它调用了Long getId方法)

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

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

    作为上面的代码片段,我们可以用Long类型实现Id匿名类。但是问题是,我们也可以实现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();方法