常量在编译阶段会存入调用这个常量的方法所在类的常量池中,本质上调用类并没有直接引用定义常量的类,因此并不会出发定义常量类的初始化。如果该常量值时动态生成的,则不会放在常量池中,会导致定义常量的类主动使用并初始化。 下面验证该结论。两个简单类的如下:

 1package com.test.jvm.learn01;
 2
 3public class Main {
 4
 5	public static void main(String[] args) {
 6		System.out.println(Consts.s);
 7	}
 8}
 9
10
11package com.test.jvm.learn01;
12
13public class Consts {
14	public static final String s = "Hello world";
15	static {
16		System.out.println("This is Consts");
17	}
18}

然后执行main方法结果如下:

 1......
 2[Loaded java.io.FilePermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 3[Loaded java.io.FilePermission$1 from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 4[Loaded java.io.FilePermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 5[Loaded java.security.AllPermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 6[Loaded java.security.UnresolvedPermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 7[Loaded java.security.BasicPermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 8[Loaded com.test.jvm.learn01.Main from file:/E:/develop/workspace/workspace-eclipse-jee-neon/JVMLearning/bin/]
 9[Loaded sun.launcher.LauncherHelper$FXHelper from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
10[Loaded java.lang.Class$MethodArray from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
11[Loaded java.lang.Void from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
12Hello world
13[Loaded java.lang.Shutdown from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
14[Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]

如果把Consts类中final关键字去掉,打印结果如下:

 1......
 2[Loaded java.nio.MappedByteBuffer from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 3[Loaded java.nio.DirectByteBuffer from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 4[Loaded java.nio.LongBuffer from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 5[Loaded java.nio.DirectLongBufferU from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 6[Loaded java.security.PermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 7[Loaded java.security.Permissions from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 8[Loaded java.net.URLConnection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 9[Loaded sun.net.www.URLConnection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
10[Loaded sun.net.www.protocol.file.FileURLConnection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
11[Loaded sun.net.www.MessageHeader from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
12[Loaded java.io.FilePermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
13[Loaded java.io.FilePermission$1 from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
14[Loaded java.io.FilePermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
15[Loaded java.security.AllPermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
16[Loaded java.security.UnresolvedPermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
17[Loaded java.security.BasicPermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
18[Loaded com.test.jvm.learn01.Main from file:/E:/develop/workspace/workspace-eclipse-jee-neon/JVMLearning/bin/]
19[Loaded sun.launcher.LauncherHelper$FXHelper from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
20[Loaded java.lang.Class$MethodArray from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
21[Loaded java.lang.Void from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
22[Loaded com.test.jvm.learn01.Consts from file:/E:/develop/workspace/workspace-eclipse-jee-neon/JVMLearning/bin/]
23This is Consts
24Hello world
25[Loaded java.lang.Shutdown from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
26[Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]

可以看到第22中加载的类com.test.jvm.learn01.Consts。在第一种情况中,定义常量的类并没有被加载,常量s的值"hello world"存放在了类类Main的常量池中,类Main和Consts没有任何关系,甚至编译之后,可以把Consts.class文件删除掉,执行运行程序都能打印出正确结果。 特别地,需要注意的是,如果常量值是在程序运行时生成的,则定义常量的类依然会被引用,如: String s = UUID.randomUUID().toString();

接着反编译Main.class文件,结果:

 1$ javap -c Main.class
 2Compiled from "Main.java"
 3public class com.test.jvm.learn01.Main {
 4  public com.test.jvm.learn01.Main();
 5    Code:
 6       0: aload_0
 7       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
 8       4: return
 9
10  public static void main(java.lang.String[]);
11    Code:
12       0: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
13       3: ldc           #22                 // String Hello world
14       5: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15       8: return
16}

第三行的注释String Hello World表明已经Hello World常量异常存储到本类的常量池中。

如果在接口中放置常量会怎么样?接口中的变量默认修饰符是public static final,所以推断接口中定义了常量不会导致该接口被主动使用。同样地,如果该常量值是动态生成的,接口会被主动使用。代码和运行结果如下:

1package com.test.jvm.learn01;
2
3public interface MyInterface {
4	int t = 20;
5}
 1[Loaded sun.misc.Perf from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 2[Loaded sun.misc.PerfCounter$CoreCounters from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 3[Loaded sun.nio.ch.DirectBuffer from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 4[Loaded java.nio.MappedByteBuffer from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 5[Loaded java.nio.DirectByteBuffer from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 6[Loaded java.nio.LongBuffer from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 7[Loaded java.nio.DirectLongBufferU from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 8[Loaded java.security.PermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
 9[Loaded java.security.Permissions from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
10[Loaded java.net.URLConnection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
11[Loaded sun.net.www.URLConnection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
12[Loaded sun.net.www.protocol.file.FileURLConnection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
13[Loaded sun.net.www.MessageHeader from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
14[Loaded java.io.FilePermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
15[Loaded java.io.FilePermission$1 from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
16[Loaded java.io.FilePermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
17[Loaded java.security.AllPermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
18[Loaded java.security.UnresolvedPermission from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
19[Loaded java.security.BasicPermissionCollection from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
20[Loaded com.test.jvm.learn01.Main from file:/E:/develop/workspace/workspace-eclipse-jee-neon/JVMLearning/bin/]
21[Loaded sun.launcher.LauncherHelper$FXHelper from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
22[Loaded java.lang.Class$MethodArray from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
23[Loaded java.lang.Void from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
2420
25[Loaded java.lang.Shutdown from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]
26[Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar]

这里有一些助记符:

  • ldc:将int,float或者String类型的常量值从常量池中推送到栈顶,即将被使用。
  • bipush:将单字节的常量值推送到栈顶
  • sipush:将-32768~32767推送到栈顶
  • iconst_1:将常量值1推送到栈顶(iconst_1~iconst_5)

另外,VM选项设置:

  • **-XX:

  • **-XX:

  • **-XX:

  • -XX:+TraceClassLoading表示开启类的追踪