Wit*_*eso 15 java static final compilation
在java中,说我有以下内容
==fileA.java==
class A
{
public static final int SIZE = 100;
}
Run Code Online (Sandbox Code Playgroud)
然后在另一个文件中我使用此值
==fileB.java==
import A;
class b
{
Object[] temp = new Object[A.SIZE];
}
Run Code Online (Sandbox Code Playgroud)
当这个被编译时会SIZE被替换为值100,所以如果我要在路上替换FileA.jar而不是FileB.jar,对象数组将获得新值或者它是否已被硬编码为100,因为那是它最初建成时的价值?
谢谢,
斯蒂芬妮
Jes*_*per 28
是的,Java编译器确实将SIZE示例中的静态常量值替换为其文字值.
因此,如果您稍后SIZE在课堂上进行更改A但不重新编译课程b,则仍会在课堂上看到旧值b.你可以轻松测试一下:
文件A.java
public class A {
public static final int VALUE = 200;
}
Run Code Online (Sandbox Code Playgroud)
文件B.java
public class B {
public static void main(String[] args) {
System.out.println(A.VALUE);
}
}
Run Code Online (Sandbox Code Playgroud)
编译A.java和B.java.现在运行:java B
更改A.java中的值.重新编译A.java,但不重新编译B.java.再次运行,您将看到打印旧值.
你可以通过这样做来保持常量不被编译成B.
class A
{
public static final int SIZE;
static
{
SIZE = 100;
}
}
Run Code Online (Sandbox Code Playgroud)
证明该行为的另一种方法是查看生成的字节码。当常数“小”时(大概 < 128):
public B();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 42
7: anewarray #3; //class java/lang/Object
10: putfield #12; //Field temp:[Ljava/lang/Object;
13: return
}
Run Code Online (Sandbox Code Playgroud)
(我使用 42 而不是 100,所以它更突出)。在这种情况下,它显然被替换在字节码中。但是,假设常数“更大”。然后你会得到如下所示的字节代码:
public B();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #12; //int 86753098
7: anewarray #3; //class java/lang/Object
10: putfield #13; //Field temp:[Ljava/lang/Object;
13: return
Run Code Online (Sandbox Code Playgroud)
当它更大时,使用操作码“ldc”,根据JVM 文档,它是“一个无符号字节,必须是当前类的运行时常量池的有效索引”。
在任何一种情况下,常量都会嵌入到 B 中。我想,由于在操作码中您只能访问当前类运行时常量池,因此将常量写入类文件的决定与实现无关(但我不这样做)事实上我不知道)。