【问题标题】:Implementing generic java interface adds additional method [duplicate]实现通用java接口添加了额外的方法[重复]
【发布时间】:2017-11-29 08:46:21
【问题描述】:

我有一个通用的 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);
    };
}

【问题讨论】:

  • 在 Returntype Long 的方法中,您还可以返回原始 long 例如return 0L;。它将自动装箱为Long。不是你的问题的答案,但也许你不知道。

标签: java generics inheritance


【解决方案1】:

第二种方法是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

【讨论】:

    【解决方案2】:

    这是功能。

    中提出了同样的问题

    JDK-8060179 Class.getDeclaredMethods() returning inconsistent results with generics 并作为“不是错误”关闭。

    【讨论】:

      【解决方案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 种方法,一个 返回类型Longimplementation,另一个 返回类型 是Object 类型(它正在调用Long getId 方法)。

      返回类型Object方法用于在没有指定泛型类型时处理,并桥接Long getId方法。示例:

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

      如上面的代码 sn-p 我们可以用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(); 方法。

      【讨论】:

        猜你喜欢
        • 2014-04-17
        • 1970-01-01
        • 2021-01-11
        • 1970-01-01
        • 2012-11-27
        • 2019-01-29
        • 2020-05-07
        • 2012-08-13
        • 1970-01-01
        相关资源
        最近更新 更多