【问题标题】:java 8 constant pool constant dependencyjava 8 常量池常量依赖
【发布时间】:2017-09-13 15:09:22
【问题描述】:

假设我在文件 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

我想知道当我只有 B.class 文件而没有源代码时,我是否可以得到值“0”的来源(A.java) 听说用java8编译时,通过读取B.class中的常量池,可以知道B.java使用了A.java中的一些常量值。 但我不太确定这一点或如何通过读取常量池来获取常量来自的实际类。

【问题讨论】:

  • I want to know if I can get where the value "0" come from 你到底是什么意思?
  • 值是一个值,它不能“来自”。对于引用类型变量来说,有一种说法是相同的值,但不是在这种情况下。
  • @procrastinator "来自" 表示这个常量值的定义位置。
  • @Andremoniy 是的,有点像参考,我只想知道当我阅读 B.class 文件时,我怎么知道值 0“来自”A.class。原谅我的表达方式。
  • @Raymond 你不是自己定义的吗?因为你的问题是这样Let's say I defined a constant int in file A.java

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


【解决方案1】:

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;

该值在编译时解析。在B 类中没有出现对A.CONSTAN_VALUE_IN_A 的引用,而是将0 的解析值编译到B 类中。

所以,不,没有办法知道B 中的值来自哪里,除非你能找到源代码。

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

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

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

【讨论】:

  • 从 iirc 的第一个版本开始。在 Java1.1 中,肯定是这样的。
  • 所以,对于 B.class 文件,我无法弄清楚它引用了 A.class 中定义的一些常量值,对吧?
  • @Raymond Guo:没错。
【解决方案2】:

几乎肯定不会。

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

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

【讨论】:

  • 虽然我不赞成你的回答,但对我来说这个问题本身没有任何意义;
  • 你的答案归结为几乎肯定不是。他们在问题中已经提到的其余部分:在我编译我的项目后,在 B.class 中,我有 [...].
  • @Andremoniy - 我对 我想知道我是否可以得到值“0”来自 (A.java) 的解释是 OP 可以告诉结果值的fooBValue(即0)来自A类。
  • @SotiriosDelimanolis - 正是我的观点 - 在构建类文件之前,源代码确实运行良好,并且在运行时肯定不会可用。
  • 我的意思是你只是在重复他们已经说过的话,而你没有做到令人信服。编辑您的答案以提供证据和证据,而不是猜测,几乎可以肯定机会非常小可能
猜你喜欢
  • 2015-08-02
  • 2013-05-17
  • 1970-01-01
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
相关资源
最近更新 更多