java 8常量池常量依赖

时间:2017-09-13 15:09:22

标签: java java-8 jvm inline java-bytecode-asm

假设我在文件A.java中定义了一个常量int:

public final static int CONSTAN_VALUE_IN_A = 0;

当我在另一个文件B.java中使用此值时:

int fooBValue = A.CONSTAN_VALUE_IN_A;

在我编译项目后,在B.class中,我有:

fooBValue = 0

我想知道我是否可以获得价值" 0"来自(A.java)当我只有没有源代码的B.class文件时。 我听说在用java8编译时,我可以知道B.java通过读取B.class中的常量池在A.java中使用了一些常量值。 但我对此并不十分肯定,或者如何通过读取常量池来获得实际类的常量。

2 个答案:

答案 0 :(得分:3)

JLS 4.12.4定义了一个“常量变量”,如下所示:

  

常量变量是基本类型或类型String的最终变量,使用常量表达式初始化(​​第15.28节)。

JLS 13.1描述了这些如何在类文件中结束:

  

3。对于作为常量变量(§4.12.4)的字段的引用必须在编译时解析为由常量变量的初始化程序表示的值V.

     

如果这样的字段是静态的,那么二进制文件中的代码中不应该存在对该字段的引用,包括声明该字段的类或接口。这样的字段必须总是看似已经初始化(§12.4.2);必须永远不要观察该字段的默认初始值(如果不同于V)。

班级A

中的声明
    public final static int CONSTAN_VALUE_IN_A = 0;

符合常量变量的定义,所以当它在类B中使用时,

    int fooBValue = A.CONSTAN_VALUE_IN_A;

该值在编译时解析。类A.CONSTAN_VALUE_IN_A中不会显示对B的引用,而是将0的已解析值编译为B类。

所以,不,除非你能找到源代码,否则没有办法告诉B中的值是哪里来的。

如果您不喜欢这种行为,可以通过更改内容来避免它,以便不满足JLS 4.12.4的条件,例如使其不是最终的,或者通过更改类型使其既不是原语也不是String。但是,使其不是常量变量的最简单方法是将初始化移动到静态初始化器中:

    public final static int CONSTAN_VALUE_IN_A;
    static {
        CONSTAN_VALUE_IN_A = 0;
    }

顺便说一句,这在Java 8中并不新鲜;这种行为已经很长时间了。

答案 1 :(得分:-1)

几乎肯定不会。

许多static final值甚至在编译时被与常量相关联的实际值替换。

static final int X = 0;
static final int Q = 9;

private void test(String[] args) {
    int x = X;
    int y = Q;
}

可能会在编译的最初阶段转变为:

private void test(String[] args) {
    int x = 0;
    int y = 9;
}

因此,发现价值实际来自哪里的机会非常很小。