首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Java编译器内联访问非静态的最终字段?

为什么Java编译器内联访问非静态的最终字段?
EN

Stack Overflow用户
提问于 2017-10-28 23:55:57
回答 1查看 1.2K关注 0票数 5

我一直在运行一些微基准,遇到了一个奇怪的问题。我使用的是java version "1.8.0_131"和默认编译器选项。

给出一个定义

代码语言:javascript
复制
public class JavaState {
    public String field = "hello";
    public final String finalField = "hello";
}

直接访问field (state.field)将生成

代码语言:javascript
复制
ALOAD 1
GETFIELD JavaState.field : Ljava/lang/String;

但是直接访问finalField (state.finalField)会生成

代码语言:javascript
复制
ALOAD 1
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
POP
LDC "hello"

Why bytecode calls Object->getClass() at a direct field access解释说,对getClass的调用只是检查state不是null,但是编译器已经内联了字段的值。

我可以合理地预期,用不同的字段值替换较晚版本的JavaState会导致其他代码在没有重新编译的情况下看到更改,但这种内联阻止了这一点。我的基准测试表明,如果它是以性能的名义完成的,它是不起作用的;至少在我的基准Raspberry上,访问finalField比访问field慢5-10%。

内联final字段值的理由是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-10-29 01:48:27

这可能是Java语言规范要求的,但细节尚不清楚。来自变量

常量变量是由常量表达式初始化的原始类型或类型字符串的最终变量(§15.28)。变量是否为常量变量可能涉及类初始化(§12.4.1)、二进制兼容性(§13.1,§13.4.9)和确定赋值(§16 (确定性赋值))。

注意,不需要变量为static。然后从第13.1节二进制的形式

对常量变量(§4.12.4)的字段的引用必须在编译时解析为由常量变量的初始化器表示的值V。 如果这样的字段是静态的. 如果这样的字段是非静态的,那么除了包含字段的类之外,二进制文件中的代码中不应该存在对字段的引用。(它将是一个类,而不是一个接口,因为接口只有静态字段。)类应该有代码,以便在实例创建期间将字段的值设置为V (§12.5)。

我不知道你的反编译代码从何而来。如果它在类之外,那么您所看到的就由规范强制执行。如果是在教室里,那就不太清楚了。您可以阅读上面引用的第三段,以暗示对字段的唯一代码引用应该在初始化字段的<init>方法中进行,但实际上并没有说明这一点。

第13.4.9款直接解决了您对二进制兼容性的关注,但它似乎明确地将自己限制在static字段(强调我的):

如果一个字段是一个常量变量(§4.12.4),则,而且是静态,那么删除关键字final或更改其值不会导致它们不运行而破坏与预先存在的二进制文件的兼容性,但是除非重新编译它们,否则它们不会看到使用该字段的任何新值。这个结果是支持条件编译的决定的一个副作用(第14.21节)。(人们可能会认为,如果使用发生在一个常量表达式中(§15.28),则不会看到新的值,但会看到不同的值。情况并非如此;预先存在的二进制文件根本看不到新值。) 要求静态常量变量值内联的另一个原因是开关语句。它们是唯一依赖常量表达式的语句,即开关语句的每个case标签必须是一个常量表达式,其值与每个其他case标签不同。case标签通常是对静态常量变量的引用,因此可能不会立即看出所有标签都有不同的值。如果证明编译时没有重复标签,那么将值内联到类文件中可以确保在运行时也没有重复标签--这是一个非常理想的属性。

由于非静态常量最终字段并不常用,也不是特别有用,因此在编写规范时,它们可能只是简单地从裂缝中滑过。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46995632

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档