我有两门课

// BaseClass.java
class BaseClass<T> {
 
   public String getTest(){
       return "one";
   }
 
   public String getTest2(T t){
       return "two";
   }
   public String getTest3(T t){
       return "three";
   }
}
 
// OverrideClass.java
public class OverrideClass extends BaseClass<Test>{
}
 

我try 运行以下代码

// Test.java
public class Test {
   public static void main(String[] args) {
       Class<OverrideClass> overrideClass = OverrideClass.class;
       Method[] declaredMethods = overrideClass.getDeclaredMethods();
       System.out.println(Arrays.toString(declaredMethods));
   }
}

我认为它应该输出

[]

但实际上输出是

[public java.lang.String OverrideClass.getTest()]

通过字节码,我认为这是一个桥接方法,但我不知道为什么它会生成,如果我将基类公开,它就会消失.

  // access flags 0x1041
  public synthetic bridge getTest()Ljava/lang/String;
   L0
    LINENUMBER 1 L0
    ALOAD 0
    INVOKESPECIAL BaseClass.getTest ()Ljava/lang/String;
    ARETURN
   L1
    LOCALVARIABLE this LOverrideClass; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1
}

我的问题是:

  1. 如果基类是默认值,为什么getTest()会生成桥接方法?
  2. 为什么getTest2()getTest3()没有生成他们的桥接方法?这似乎与泛型有关.

谢谢你的帮助!

推荐答案

我已经分析了这个问题,下面是结果.我把问题中的例子简化了一点.

这个答案处理OP的第一个问题

如果基类是默认的,为什么getTest()会生成一个桥方法?

关于泛型出现的不一致性的第二个问题,您可以阅读Denis answer

示例1

class BaseClass {

    public String getTest(){
        return "one";
    }

    public String getTest2(){
        return "two";
    }
    public String getTest3(){
        return "three";
    }
}


public class OverrideClass extends BaseClass{}


public class Application {

public static void main(String[] args) throws Exception {
    Class<OverrideClass> overrideClass1 = OverrideClass.class;
    Method[] declaredMethods1 = overrideClass1.getDeclaredMethods();
    System.out.println(Arrays.toString(declaredMethods1));
   }
}

使用JDK 8或JDK 17执行此操作的结果始终相同

[public java.lang.String OverrideClass.getTest(), public java.lang.String OverrideClass.getTest2(), public java.lang.String OverrideClass.getTest3()]

示例2

只需将上述示例修改为

public class BaseClass {

    public String getTest(){
        return "one";
    }

    public String getTest2(){
        return "two";
    }
    public String getTest3(){
        return "three";
    }
}

请注意,更改发生在基类上的访问修饰符中,现在是public

执行此操作将产生[]的预期行为

然而,这并不是JDK的一个bug.其目的是这样.

解释

在示例1中,getDeclaredMethods()返回父类的相同方法的原因并不是因为这些方法被打印为继承的.这是因为这些是实际上属于该子类(OverrideClass)的桥接方法.

这个功能很久以前就添加了,您可以从oracle开发人员那里看到here条解释是

建议在这些非常罕见的情况下添加桥接方法来修复

正如您还可以看到的here,oracle开发人员最近的 comments 是

桥接方法是在这样的情况下添加的,其中一个公共类

将此问题作为错误关闭.

因此,这只发生在非公共父类中,因为在这种情况下,继承的公共方法需要作为桥接方法添加到子类中.

example 2中不存在桥接方法,如果您try 使用javap -c OverrideClass打印反汇编代码,您将看到以下内容

public class OverrideClass extends BaseClass {
      public OverrideClass();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method BaseClass."<init>":()V
           4: return
    }

在现有桥接方法的example 1中,如果您try 使用javap -c OverrideClass打印反汇编代码,您将看到以下内容

public class OverrideClass extends BaseClass {
  public OverrideClass();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method BaseClass."<init>":()V
       4: return

  public java.lang.String getTest3();
    Code:
       0: aload_0
       1: invokespecial #7                  // Method BaseClass.getTest3:()Ljava/lang/String;
       4: areturn

  public java.lang.String getTest2();
    Code:
       0: aload_0
       1: invokespecial #11                 // Method BaseClass.getTest2:()Ljava/lang/String;
       4: areturn

  public java.lang.String getTest();
    Code:
       0: aload_0
       1: invokespecial #14                 // Method BaseClass.getTest:()Ljava/lang/String;
       4: areturn
}

Java相关问答推荐

具有额外列的Hibert多对多关系在添加关系时返回NonUniqueHealthExcellent

JPackaged应用程序启动MSI调试,然后启动System. exit()

在spring—data中自动发现native—sql查询期间遇到重复的SQL别名[id]

路径映射未发生

Jlink选项&-strie-ative-Commands";的作用是什么?

JavaFX Maven Assembly插件一直打包到错误的JDK版本

将带有js文件的 bootstrap 程序导入maven项目时出错

如何在ApachePOI中将图像添加到工作表的页眉?

Java:使用Class.cast()将对象转换为原始数组

第二次按下按钮后,我需要将按钮恢复到其原始状态,以便它可以再次工作

如何从日志(log)行中删除包名称?

如何创建模块信息类文件并将其添加到JAR中?

一对多关系和ID生成

Java组件项目中的JavaFX对话框国际化

使用for循环时出现堆栈溢出错误,但如果使用if块执行相同的操作,则不会产生错误

对角线填充二维数组

如何调整JButton的大小以适应图标?

通过/失败的参数化junit测试方法执行数

Spring Boot Security-每个端点都被403禁止,Spring记录一个BasicErrorController#错误(HttpServlet请求)

如何在Java中正确实现填字游戏求解器