这通常不适用于Java.访问检查仅在解决过程中执行一次.当Java方法进行JIT编译时,符号引用已经过解析和验证.实际上,内联不是在原始字节码上执行,而是在编译器特定的中间表示上执行.因此,访问修饰符通常不具有性能副作用.
但是,我可以编写一个人工测试用例,其中private/ publicmodifier会显着影响性能:
public class Test {
static final Inner inner = new Inner();
static class Inner {
int x = 1;
int getX1() { return x; }
int getX2() { return getX1(); }
int getX3() { return getX2(); }
int getX4() { return getX3(); }
int getX5() { return getX4(); }
int getX6() { return getX5(); }
int getX7() { return getX6(); }
int getX8() { return getX7(); }
int getX9() { return getX8(); }
private int getPrivate() { return getX9(); }
public int getPublic() { return getX9(); }
}
@GenerateMicroBenchmark
public int inlinePrivate() {
return inner.getPrivate();
}
@GenerateMicroBenchmark
public int inlinePublic() {
return inner.getPublic();
}
}
Run Code Online (Sandbox Code Playgroud)
Benchmark Mode Thr Cnt Sec Mean Mean error Units
b.Test.inlinePrivate thrpt 1 3 5 289480,928 2247,656 ops/msec
b.Test.inlinePublic thrpt 1 3 5 1157970,245 18473,139 ops/msec
Run Code Online (Sandbox Code Playgroud)
这种效果通过合成方法说明access$000,其javac生成以允许接近内部类的私有成员.在上面的测试用例中,这个额外的访问器阻止了内联,因为HotSpot中默认的最大内联级别是9(-XX:MaxInlineLevel=9).由于getPrivate()不能直接从外部类access$000()调用,因此额外的方法调用了10级,因此没有内联.
我不是“编译器决策”方面的专家,但从逻辑上讲我会说:
让我们想象一下这两个类(例如在 Java 中):
class A {
private B b;
public void execute(){
b.execute();
}
}
class B {
private int number;
public void execute {
println(number);
}
}
Run Code Online (Sandbox Code Playgroud)
如果 B'sexecute由编译器内联到 A's 中execute,则会导致非法访问,因为number在 B 中是私有的:
class A {
private B b;
public void execute(){
println(number); //OUPS! number is unreachable directly from A
}
}
Run Code Online (Sandbox Code Playgroud)
所以我想说,当您期望一些“内联”时,最好避免一些不兼容的变量范围。
当然,我认为它在极少数情况下很有用(主要是为了性能优化,我不想象其他情况)..也许是你展示的情况,否则会导致很多“糟糕的封装”...