StringTabele
常量池分类
- Class文件中的常量池
这里面主要存放两大类常量:- 字面量(Literal):文本字符串等
- 符号引用(Symbolic References):属于编译原理方面的概念,包含三类常量:
- 类和接口的全限定名(Full Qualified Name)
- 字段的名称和描述符(Descriptor)
- 方法的名称和描述符
- 运行时常量池
方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池(Constant Pool Table),存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池。 - 全局字符串常量池StringTable
HotSpot VM里,记录interned string的一个全局表叫做StringTable,它本质上就是个HashSet。这是个纯运行时的结构,而且是惰性(lazy)维护的。注意它只存储对java.lang.String实例的引用,而不存储String对象的内容。 注意,它只存了引用,根据这个引用可以得到具体的String对象。
一般我们说一个字符串进入了全局的字符串常量池其实是说在这个StringTable中保存了对它的引用,反之,如果说没有在其中就是说StringTable中没有对它的引用。
String的基本特性
-
String:字符串,使用一对 “” 引起来表示
String s1 = "mogublog" ; // 字面量的定义方式 String s2 = new String("moxi"); // new 对象的方式 -
String声明为final的,不可被继承
-
String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小
-
string在jdk8及以前内部定义了final char[] value用于存储字符串数据。JDK9时改为byte[],同时基于String的数据结构,例如StringBuffer和StringBuilder也同样做了修改
jdk8及以前:

jdk9及以后:

为什么 JDK9 改变了 String 的结构(char改为byte)
改为 byte[] 存储的原因

- char数组中,每个字符使用两个字节(16位)。
- 从许多不同的应用程序收集的数据表明,字符串是堆使用的主要组成部分,而且大多数字符串对象只包含拉丁字符。这些字符只需要一个字节的存储空间,因此这些字符串对象的内部char数组中有一半的空间将不会使用。

- 因此String再也不用char[] 来存储了,改成了byte [] 加上编码标记,节约了一些空间
之前 String 类使用 UTF-16 的 char[] 数组存储,现在改为 byte[] 数组 外加一个编码标志位存储,该编码标志将指定 String 类中 byte[] 数组的编码方式
-
String:代表不可变的字符序列。简称:不可变性。
-
通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
-
字符串常量池是不会存储相同内容的字符串的,因为底层用的hashtable
Java语言规范里要求完全相同的字符串字面量,应该包含同样的Unicode字符序列(包含同一份码点序列的常量),并且必须是指向同一个String类实例。

面试题

String 底层 Hashtable 结构
- String的String Pool是一个固定大小的Hashtable
hashtable就是数组加链表 - 使用-XX:StringTablesize可设置StringTable的长度
- StringTable的长度是固定的,不同的jdk版本默认值不一样
-
在JDK6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快,StringTablesize设置的大小没有要求

-
在JDK7中,StringTable的长度默认值是60013,StringTablesize设置的大小没有要求

-
在JDK8中,StringTable的长度默认值是60013,StringTable可以设置的最小值为1009
设置的值小于1009就报错了

-
为什么要idk要增大stringtable的长度
如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern()方法时性能会大幅下降。
String 内存结构的分配位置
-
在Java语言中有8种基本数据类型和一种比较特殊的类型String。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。
-
常量池就类似一个Java系统级别提供的缓存。8种基本数据类型的常量池都是系统协调的,String类型的常量池比较特殊。它的主要使用方法有两种。
- 直接使用双引号声明出来的String对象会直接存储在常量池中。
比如:String info=“atguigu.com”; - 如果不是用双引号声明的String对象,可以使用String提供的intern()方法。
- 直接使用双引号声明出来的String对象会直接存储在常量池中。
String在不同jdk版本中存在的位置
-
Java 6及以前,字符串常量池存放在永久代

-
Java 7中 Oracle的工程师对字符串池的逻辑做了很大的改变,即将字符

本文详细介绍了JVM中StringTable的结构及其作用,讲解了String对象在不同JDK版本下的内存分配变化,以及String的基本特性和操作。探讨了字符串拼接的底层原理和效率,强调了intern()方法的使用和性能优化,同时还涉及G1垃圾收集器中的String去重操作,旨在帮助读者深入理解Java中字符串的管理和内存优化。

1380

被折叠的 条评论
为什么被折叠?



