方法/字段可见性对 Java 中的方法内联有何影响?
我想到的情况类似于 private
字段的 public
getter:
private Thing blah;
public Thing getBlah() {
return blah;
}
这里出现了几个问题。
首先,Java 编译器本身是否会进行内联?这个问题似乎有不同的答案,有些人说 yes有人说no 。我不知道这是因为它以前不做任何内联,但现在做了,还是只是有些人是对的,有些人是错的......
现在,如果它确实做了一些内联,我认为它不可能内联 getBlah() 调用是正确的吗?它们显然是内联有用的地方,因为该方法非常简单,并且调用方法的开销与方法本身的代码一样大。但如果它被编译器内联,您最终会得到直接访问 private
字段的字节码;那么 JVM 肯定会提示吗? (即使此方法是static final
,这也适用。)
其次,JIT 编译器怎么样?据我所知,当涉及到该级别的内联时,这个问题并不适用。一旦生成 native 代码,JVM 就已经完成了检查,并确认我可以调用该方法(因为它是 public
);这样它就可以生成内联调用的 native 代码,而不会出现任何可见性问题...是吗?
最佳答案
javac 编译器(以及任何有效的 java 编译器)不会也不可能内联 getters;想一想:您可以从该类扩展一个类并覆盖 getter。是的,如果编译器过度热心地内联该访问,它将无法通过验证程序(至少它不应该通过验证程序,但它们不会验证所有内容 - 在 java 1.3 中,您甚至可以使 main () 私有(private),它仍然可以工作...同样,javac 中曾经有一个 -O 选项,确实有时会搞砸你的代码)。
JIT 完全是另外一头野兽;它随时知道(至少现在是这样)是否存在方法的覆盖。即使稍后加载一个覆盖 getter 的类,它也可以对已经 JIT 的方法进行去优化,以反射(reflect)继承树上的更改(这是 AOT 编译器缺乏信息的优化之一)。 p>
因此它可以安全地内联任何它想要的内容。它也不需要人为地维护访问修饰符,因为编译后的机器代码中没有这样的东西,并且它再次知道什么是有效的代码转换(并且由于 getter 如此常见,因此对于 JIT 来说,它也是一个容易实现的目标)优化)。
编辑:为了绝对清楚,上面的段落讨论了潜在的虚拟方法;特别是那些不是私有(private)的、静态的或最终的。 Javac 在某些情况下可以执行内联;因为它可以证明对于这些来说不存在覆盖。考虑到 JIT 也在做这件事,而且做得更好,这将是一项毫无意义的工作。
关于java - 可见性和 javac/JVM 内联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26144822/