首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >有没有可能禁用javac的静态最终变量内联?

有没有可能禁用javac的静态最终变量内联?
EN

Stack Overflow用户
提问于 2010-08-20 00:53:09
回答 9查看 8.5K关注 0票数 56

Java静态编译器(javac)内联一些静态final变量,并将值直接带入常量池。考虑下面的例子。类A定义了一些常量(公共静态最终变量):

public class A {
    public static final int INT_VALUE = 1000;
    public static final String STRING_VALUE = "foo";
}

类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);
    }
}

在编译B类时,javac从A类获取这些常量的值,并将这些值内联到B.class中。因此,在编译时必须对类A的依赖项B从字节码中删除。这是一个相当奇怪的行为,因为在编译时,您正在烘焙这些常量的值。您可能认为这是JIT编译器在运行时可以做的最简单的事情之一。

有没有什么方法或隐藏的编译器选项可以让你禁用javac的这种内联行为?作为背景,我们正在研究进行字节码分析以实现依赖关系,这是字节码分析无法检测到编译时依赖关系的少数情况之一。谢谢!

编辑:这是一个令人烦恼的问题,因为通常我们不能控制所有的源代码(例如,定义常量的第三方库)。我们感兴趣的是使用常量的角度来检测这些依赖关系。由于引用是从使用常量的代码中删除的,因此没有简单的方法来检测它们,除非进行源代码分析。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2010-08-20 01:11:23

Java Puzzler (Joshua Bloch)的第93条指出,您可以通过防止最终值被视为常量来解决此问题。例如:

public class A {
  public static final int INT_VALUE = Integer.valueOf(1000).intValue();
  public static final String STRING_VALUE = "foo".toString();
}

当然,如果您不能访问定义常量的代码,那么这些都是不相关的。

票数 46
EN

Stack Overflow用户

发布于 2010-08-20 01:02:47

我想不行。最简单的解决方法是将这些内容公开为属性而不是字段:

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;
    }
}

不要忘记,在某些情况下,内联对于值的使用是必不可少的-例如,如果要在转换块中使用INT_VALUE作为大小写,则必须将其指定为常量值。

票数 14
EN

Stack Overflow用户

发布于 2010-08-20 02:04:10

要停止内联,需要将这些值设为非编译时间常量( JLS术语)。通过在初始化器表达式中使用null,您可以在不使用函数和创建最少字节码的情况下完成此操作。

public static final int INT_VALUE = null!=null?0: 1000;

尽管它在代码生成中非常简单,但javac应该将其优化为在静态初始化器中推送一个立即整数,然后存储到静态字段。

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

https://stackoverflow.com/questions/3524150

复制
相关文章

相似问题

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