您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

当在子类上调用其父类中声明的静态方法时,为什么不调用子类的静态初始化器?

当在子类上调用其父类中声明的静态方法时,为什么不调用子类的静态初始化器?

我认为这与jvm规范的这一部分有关:

每个框架(第2.6节)都包含对当前方法类型的运行时常量池(第2.5.5节)的引用,以支持方法代码的动态链接方法的类文件代码是指要调用方法和要通过符号引用访问的变量。动态链接将这些符号方法引用转换为具体的方法引用,根据需要加载类以解析尚未定义的符号,并将变量访问转换为与这些变量的运行时位置关联的存储结构中的适当偏移量。

方法和变量的这种较晚的绑定使方法使用的其他类中的更改不太可能破坏此代码

在jvm规范的第5章中,他们还提到:由于以下原因,可能会初始化类或接口C:

执行引用C的Java虚拟机指令new,getstatic,putstatic或invokestatic的任何一条(§new,§getstatic,§putstatic,§invokestatic)。这些指令通过字段引用或方法引用 引用类或接口。

在执行getstatic,putstatic或invokestatic指令后,如果尚未 则将对其进行初始化。

在我看来,文档的第一部分似乎指出,任何符号引用都可以简单地解析和调用,而不考虑其来源。关于方法解析的文档对此有以下说法:

[M] ethod解析尝试在C及其超类中定位引用的方法

如果C完全使用方法引用指定的名称声明了一个方法,并且声明是签名多态方法(第2.9节),则方法查找成功。描述符中提到的所有类名都将被解析(第5.4.3.1节)。

解析的方法是签名多态方法声明。C不必使用方法参考指定的描述符来声明方法

否则,如果C使用方法参考指定的名称和描述符声明方法,则方法查找成功。

否则,如果C具有超类,则对C的直接超类递归调用方法解析的步骤2。

因此,从子类调用它的事实似乎被忽略了。为什么要这样呢?在您提供的文档中,他们说:

目的是类或接口类型具有一组初始化器,这些初始化器将其置于一致状态,并且该状态是其他类观察到的第一个状态。

在您的示例中,当Sub静态初始化时,您更改了Super的状态。如果在调用Sub.staticMethod时发生初始化,则jvm认为相同方法的行为会有所不同。这可能是他们在谈论要避免的不一致之处。

另外,这是一些执行staticMethod的反编译类文件代码显示了invokestatic的使用:

Constant pool:
    ...
    #2 = Methodref          #18.#19        // Sub.staticMethod:()V

...

Code:
  stack=0, locals=1, args_size=1
     0: invokestatic  #2                  // Method Sub.staticMethod:()V
     3: return
其他 2022/1/1 18:26:54 有567人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶