如果您想了解关于几个常量池之间的知识,请您看这篇JVM的常量池:什么是字符串常量池、运行时常量池、Class常量池
大致过程:
在该类的class常量池中会存放一些符号引用,在类加载之后,会将class常量池中存放的符号引用加载到内存中的运行时常量池中,然后经过验证,准备阶段之后,会在堆中生成驻留字符串的实例对象(也就是””括起来的),然后将这个对象的引用存到全局String Pool中,也就是StringTable中,最后在解析阶段,要把运行时常量池中的符号引用替换成直接引用,通过直接查询StringTable,保证运行时常量池里的引用值与字符串常量池中的引用值一致。
一、字符常量如何进入常量池
8种基本类型的常量池都是系统协调的但String类型比较特殊,之后的运行过程涉及到常量池内容添加和String对象的两种创建方式的关系:
(1)String str1 = "abcd"
采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"abcd"这个对象,如果常量池是空的会直接在字符串常量池中创建该双引号声明出来的 String 对象,然后将池中"abcd"这个对象的引用地址返回给对象的引用str1,如果存在,则不创建任何对象,直接将池中"abcd"这个对象的地址返回。
(2)String str1 = new String("abcd")
采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"abcd"这个字符串对象,如果没有,则首先在字符串池中创建一个"abcd"字符串对象,然后再在堆中创建一个"abcd"字符串对象,然后将堆中这个"abcd"字符串对象的地址返回赋给str1引用,如果有,则不在常量池中再去创建"abcd"这个对象了,直接在堆中创建一个"abcd"字符串对象,然后将堆中的这个"abcd"对象的地址返回赋给引用。
(3)通过String.intern()
intern()方法设计的初衷,就是重用String对象,以节省内存消耗,String对象可以使用 String.intern()来动态的进入常量池,intern() 方法返回字符串对象的规范化表示形式,它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
二、对String.intern()的理解
String.intern() 是一个 Native 方法,以下是文档内容:
《java虚拟机规范 Java SE 8版》记录,如果某String实例所包含的Unicode码点序列与CONSTANT——String_info结构所给出的序列相同也就是字符连起来通过equals()比较是否相同,而之前又曾在该实例上面调用过String.intern方法,那么此次字符串常量获取的结果将是一个指向相同String实例的引用。