JVM中字符串常量池StringTable在内存中形式分析
字符串常量池(StringTable)
JVM中翻译字符串常量池(StringTable)为“String类型常量表”更合适,常量表它存储以双引号包住的String对象的地址引用,而不是String对象本身。通过StringTable可以实现相同内容的字符串共享。 在Java 8,StringTable是存放在内存堆中。(注意与Constant Pool的区别)。
以下两类会纳入“字符串常量表StringTable”管理:
- 已双引号包住形式申明的字符串String对象
- String对象intern()方法获得的String对象
而:其他方式如new String方式得到的String对象,不会纳入“字符串常量表StringTable”管理
下面分别展示和分析说明。
背景知识:通过java.lang.String的源代码分析,String类的内部是采用char [] 数组存放字符串的内容的。 (JDK9中实现已改为byte[]。鉴于JDK8使用者较多,下文仍以JDK8版本进行讨论)
-
双引号赋值
以上代码 执行过程:
- 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
- 由于双引号“11”他是一个String的对象,既先创建new一个String对象(图中橙色区左上角的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。 到这步完成双引号“11”对象的创建。
- 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区两个向上的蓝色箭头)。 到这步完成新String对象加入“字符串常量表”。
- 将刚刚纳入“字符串常量表StringTable”管理的String对象地址,赋值给变量s1(上图左侧的蓝色箭头)。
-
new String方式
以上代码 执行过程:
- 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
- 由于双引号“11”他是一个String的对象,既先创建new一个String对象(上图中橙色区中间的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。 到这步完成双引号“11”对象的创建。
- 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区左下角的两个向上的蓝色箭头)。 到这步完成新String对象加入“字符串常量表”。
- 执行上面代码中“new String”。 (可查看java.lang.String的源代码)既 创建一个新的String对象(上图中橙色区左上角的白色椭圆形),然后将刚刚纳入“字符串常量表StringTable”管理的String对象地址,赋值个这个新的String对象(上图中橙色区右上角的蓝色箭头)。
- 把第4步中创建的String对象,赋值给变量s1(上图左侧的蓝色箭头)。
-
两句双引号(内容相同)
以上第一句代码 执行过程:
- 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
- 由于双引号“11”他是一个String的对象,既先创建new一个String对象(图中橙色区左上角的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。 到这步完成双引号“11”对象的创建。
- 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区两个向上的蓝色箭头)。 到这步完成新String对象加入“字符串常量表”。
- 在新new的String对象地址,赋值给变量s1(上图左侧下方蓝色箭头)。
以上第二句代码 执行过程:
- 由于是String类型,需要纳入“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。(这里已经存在)。
- 从“字符串常量表StringTable”中找到的String对象地址,赋值给变量s2(上图左侧上方蓝色箭头)。
-
两个new String
以上第一句代码 执行过程:
- 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
- 由于双引号“11”他是一个String的对象,既先创建new一个String对象(上图中橙色区最下面的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。 到这步完成双引号“11”对象的创建。
- 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区左下角的两个蓝色箭头)。 到这步完成新String对象加入“字符串常量表”。
- 执行上面代码中“new String”。 (可查看java.lang.String的源代码)既 创建一个新的String对象(上图中橙色区左上角下方的白色椭圆),然后将刚刚纳入“字符串常量表StringTable”管理的String对象地址,赋值个这个新的String对象(上图中橙色区左上角下方的白色椭圆)。
- 把第4步中创建的String对象,赋值给变量s1(上图左侧下方蓝色箭头)。
以上第二句代码 执行过程:
- 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。(这里已经存在)。
- 执行上面代码中“new String”。 (可查看java.lang.String的源代码)既 创建一个新的String对象(上图中橙色区左上角上方的白色椭圆),然后从“字符串常量表”StringTable中找到的String对象地址,赋值个这个新的String对象(上图中橙色区左上角上方的白色椭圆)。
- 把第2步中创建的String对象,赋值给变量s2(上图左侧上方蓝色箭头)。