概述
Java运行时常量池是JVM运行时内存模型的重要部分.我对常量池的理解大都来自于周志明大大的《深入理解Java虚拟机》, 书中对常量池有较多的描述与解释, 在内存管理, 类文件结构等部分章节中都有说明.
正如我之前的博文–JVM内存管理对常量池描述的一样,常量池会存储字面量和符号引用,但我有个疑问:
常量池与final修饰符的关系是怎么样的?
Code
public class Test{
public static Test test = new Test();
public final Test test2 = new Test();
public final static String s1 = "1";
public static String s2 = "2";
public String s3 = "3";
public Test(){
}
public static void stMethod(){
final int sla = 10;
final String sls = "slsv";
}
public void tMethod(int tp){
final int la = 11;
final String ls = "lsv";
}
}
反编译后的常量池部分代码
public class Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #10.#30 // java/lang/Object."<init>":()V
#2 = Class #31 // Test
#3 = Methodref #2.#30 // Test."<init>":()V
#4 = Fieldref #2.#32 // Test.test2:LTest;
#5 = String #33 // 3
#6 = Fieldref #2.#34 // Test.s3:Ljava/lang/String;
#7 = Fieldref #2.#35 // Test.test:LTest;
#8 = String #36 // 2
#9 = Fieldref #2.#37 // Test.s2:Ljava/lang/String;
#10 = Class #38 // java/lang/Object
#11 = Utf8 test
#12 = Utf8 LTest;
#13 = Utf8 test2
#14 = Utf8 s1
#15 = Utf8 Ljava/lang/String;
#16 = Utf8 ConstantValue
#17 = String #39 // 1
#18 = Utf8 s2
#19 = Utf8 s3
#20 = Utf8 <init>
#21 = Utf8 ()V
#22 = Utf8 Code
#23 = Utf8 LineNumberTable
#24 = Utf8 stMethod
#25 = Utf8 tMethod
#26 = Utf8 (I)V
#27 = Utf8 <clinit>
#28 = Utf8 SourceFile
#29 = Utf8 Test.java
#30 = NameAndType #20:#21 // "<init>":()V
#31 = Utf8 Test
#32 = NameAndType #13:#12 // test2:LTest;
#33 = Utf8 3
#34 = NameAndType #19:#15 // s3:Ljava/lang/String;
#35 = NameAndType #11:#12 // test:LTest;
#36 = Utf8 2
#37 = NameAndType #18:#15 // s2:Ljava/lang/String;
#38 = Utf8 java/lang/Object
#39 = Utf8 1
可以看到, 常量池中并没有存储test2的值, 只存储了test2这个符号, 所以引用类型有final修饰符也不会进入常量池, 而没有final修饰符的s2, s3都进入了常量池(当然原因是他们是字面量), 可以看到是否进入常量池与final修饰符是没有关系的.