方法的可见性及其成本
Visibility of Methods and their cost
我最近读了 Jake Wharton 的 this article。这是针对 Android,但我认为也完全适用于 java。
考虑以下代码:
public class A {
private String someField = "abc";
class B {
public void doSomething() {
System.out.println(someField);
}
}
}
我们有一个简单的 class A 和一个内部的 class B(它有一个对 A 的引用并且可以访问它的成员)。 Class B 正在访问 A 中的字段 someField
,即使它是私有的。根据这篇文章,这是由生成 synthetic accessor methods
的编译器完成的,它允许内部 class 访问该字段。
现在我的方式更基本的问题:为什么编译器在编译代码时甚至关心可见性?正如我们在这个例子中看到的,生成了一个新方法,基本上只是引入了开销。
可见性对于构建好的软件来说是一件好事,但如果编译器根据声明的可见性完成检查一切是否正确,为什么不优化这些方法(例如,把所有东西都当作 public 并允许调用它)?
起初我认为这是出于安全原因,但反射允许访问所有字段,据我所知不关心可见性。
这可能是我的基本误解,如果是这样,如果有人能向我解释一下,我会很高兴。
如果编译器在编译时将所有私有字段都转换为public字段,那么当你的项目编译成库并被其他人重用时,就会出现一个问题。在这种情况下,您所有的私有字段都将变为 public。
有一些工具可以对此进行优化。在Android中,有一个名为ProGuard
的工具,可以将所有getter/setter转换为直接字段访问。
Why does the compiler even care about visiblities when the code is compiled?
JVM 不允许在 class 之外访问 private
methods/constructors/fields。嵌套classes没有特殊规则,是在设计这个规则后加入的。相反,编译器添加了访问器方法,因此该语言可以支持 JVM 不支持的访问方式。
As we have seen in this example, a new method is generated, which basically just introduces overhead.
仅当方法调用次数不多且未优化时。
添加任何简单的方法(在 Hotspot 上,任何 35 字节或更少的方法)都将很快内联并且对性能没有影响(除非达到最大内联级别)
why not optimize those methods away
它在运行时执行此操作,以便继续执行以前的规则。
reflection allows the access of all fields, not caring for visibility as far as I know.
虽然不是默认情况,但您必须明确希望将其作为一个选项,并且没有阻止它的 SecurityManager。
我最近读了 Jake Wharton 的 this article。这是针对 Android,但我认为也完全适用于 java。
考虑以下代码:
public class A {
private String someField = "abc";
class B {
public void doSomething() {
System.out.println(someField);
}
}
}
我们有一个简单的 class A 和一个内部的 class B(它有一个对 A 的引用并且可以访问它的成员)。 Class B 正在访问 A 中的字段 someField
,即使它是私有的。根据这篇文章,这是由生成 synthetic accessor methods
的编译器完成的,它允许内部 class 访问该字段。
现在我的方式更基本的问题:为什么编译器在编译代码时甚至关心可见性?正如我们在这个例子中看到的,生成了一个新方法,基本上只是引入了开销。
可见性对于构建好的软件来说是一件好事,但如果编译器根据声明的可见性完成检查一切是否正确,为什么不优化这些方法(例如,把所有东西都当作 public 并允许调用它)?
起初我认为这是出于安全原因,但反射允许访问所有字段,据我所知不关心可见性。
这可能是我的基本误解,如果是这样,如果有人能向我解释一下,我会很高兴。
如果编译器在编译时将所有私有字段都转换为public字段,那么当你的项目编译成库并被其他人重用时,就会出现一个问题。在这种情况下,您所有的私有字段都将变为 public。
有一些工具可以对此进行优化。在Android中,有一个名为ProGuard
的工具,可以将所有getter/setter转换为直接字段访问。
Why does the compiler even care about visiblities when the code is compiled?
JVM 不允许在 class 之外访问 private
methods/constructors/fields。嵌套classes没有特殊规则,是在设计这个规则后加入的。相反,编译器添加了访问器方法,因此该语言可以支持 JVM 不支持的访问方式。
As we have seen in this example, a new method is generated, which basically just introduces overhead.
仅当方法调用次数不多且未优化时。
添加任何简单的方法(在 Hotspot 上,任何 35 字节或更少的方法)都将很快内联并且对性能没有影响(除非达到最大内联级别)
why not optimize those methods away
它在运行时执行此操作,以便继续执行以前的规则。
reflection allows the access of all fields, not caring for visibility as far as I know.
虽然不是默认情况,但您必须明确希望将其作为一个选项,并且没有阻止它的 SecurityManager。