sjl*_*lee 53 java dependencies bytecode javac
Java静态编译器(javac)内联一些静态最终变量,并将值直接带到常量池.请考虑以下示例.A类定义了一些常量(公共静态最终变量):
public class A {
public static final int INT_VALUE = 1000;
public static final String STRING_VALUE = "foo";
}
Run Code Online (Sandbox Code Playgroud)
B类使用以下常量:
public class B {
public static void main(String[] args) {
int i = A.INT_VALUE;
System.out.println(i);
String s = A.STRING_VALUE;
System.out.println(s);
}
}
Run Code Online (Sandbox Code Playgroud)
编译类B时,javac从类A获取这些常量的值,并在B.class中内联这些值.结果,编译时必须从A类中删除的依赖关系B从字节码中删除.这是一种相当奇特的行为,因为您在编译时正在烘焙这些常量的值.你会认为这是JIT编译器在运行时可以做的最容易的事情之一.
是否有任何方法或任何隐藏的编译器选项可以禁用javac的这种内联行为?对于后台,我们正在考虑进行字节码分析以实现依赖性目的,并且它是字节码分析无法检测编译时依赖性的少数情况之一.谢谢!
编辑:这是一个棘手的问题,因为通常我们不控制所有源(例如,定义常量的第三方库).我们有兴趣从使用常量的角度检测这些依赖关系.由于引用是从使用常量的代码中删除的,因此没有简单的方法来检测它们,缺少源代码分析.
DJC*_*rth 44
Java Puzzlers(Joshua Bloch)的第93项说,你可以通过防止最终值被视为常数来解决这个问题.例如:
public class A {
public static final int INT_VALUE = Integer.valueOf(1000).intValue();
public static final String STRING_VALUE = "foo".toString();
}
Run Code Online (Sandbox Code Playgroud)
当然,如果您无法访问定义常量的代码,那么这些都不相关.
Jon*_*eet 13
我不相信.最简单的解决方法是将这些作为属性而不是字段公开:
public class A {
private static final int INT_VALUE = 1000;
private static final String STRING_VALUE = "foo";
public static int getIntValue() {
return INT_VALUE;
}
public static String getStringValue() {
return STRING_VALUE;
}
}
Run Code Online (Sandbox Code Playgroud)
不要忘记,在某些情况下,内联对于值的使用至关重要 - 例如,如果您要INT_VALUE在开关块中用作案例,则必须将其指定为常量值.
要停止内联,您需要使值为非编译时常量(JLS术语).您可以在不使用函数的情况下执行此操作,并通过null在初始化表达式中使用a 来创建最少的字节码.
public static final int INT_VALUE = null!=null?0: 1000;
Run Code Online (Sandbox Code Playgroud)
虽然它在代码生成方面非常直观,但javac应优化它是推送一个立即整数,然后存储到静态初始化器中的静态字段.
JLS 13.4.9处理此问题.他们的建议是,如果值以任何可能的方式改变,基本上避免编译时常量.
(需要内联常量的一个原因是switch语句在每种情况下都需要常量,并且没有两个这样的常量值可能是相同的.编译器在编译时检查switch语句中的重复常量值;类文件格式不做案例值的象征性联系.)
在广泛分布的代码中避免"不稳定常量"问题的最好方法是将编译时常量声明为仅真正不可能改变的值.除了真正的数学常量之外,我们建议源代码非常节省地使用声明为static和final的类变量.如果需要final的只读性质,更好的选择是声明私有静态变量和合适的访问器方法来获取其值.因此我们建议:
Run Code Online (Sandbox Code Playgroud)private static int N; public static int getN() { return N; }而不是:
Run Code Online (Sandbox Code Playgroud)public static final int N = ...;没有问题:
Run Code Online (Sandbox Code Playgroud)public static int N = ...;如果N不必是只读的.
| 归档时间: |
|
| 查看次数: |
7453 次 |
| 最近记录: |