String类
String是定义在java.lang包下的一个类,它不是基本数据类型。
String对象内容是不可变的,JVM使用字符串池来储存所有的字符串对象。
字符串常量池
引入的原因及目标
字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能。
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化:
为字符串开辟一个字符串常量池,类似于缓存区。
创建字符串常量时,首先坚持字符串常量池是否存在该字符串。
存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中。
实现的基础
实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享。
运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。
扩展:静态常量池、运行时常量池、字符串常量池
静态常量池
每个class一份,存在于字节码文件中。常量池中有字面量(数量值、字符串值)和符号引用(类符号引用、字段符号引用、方法符号引用),虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型
运行时常量池
每个class一份,存在于方法区中(元空间)。当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,经过解析(resolve)之后,也就是把符号引用替换为直接引用,解析的过程会去查询全局字符串池,也就是下面的StringTable,以保证运行时常量池所引用的字符串与全局字符串池中所引用的是一致的。
字符串常量池
每个JVM中只有一份,存在于方法区中(堆)。全局字符串池里的内容是在类加载完成,经过验证,准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例的引用值存到string pool中(string pool中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的)。 在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个哈希表,里面存的是驻留字符串(用双引号括起来的引用而不是驻留字符串实例本身),也就是说在堆中的某些字符串实例被这个StringTable引用之后就等同被赋予了”驻留字符串”的身份。
常用方法
如substring、contains、format、replace等
注意事项
String类实例对象指向地址的内容不可变,指向的地址可变
String不可变优点:
方便做hash中的key
方便使用String pool
方便做方法参数
线程安全(实现中的char数组被final修饰,JDK9后使用byte数组)
String类拼接存在性能问题
String类不能被继承(String 类被声明成final类型)
比较方法equals与==区别
String、StringBuilder、StringBuffer与线程安全
String | StringBuilder | StringBuffer | |
线程安全 | true | false | true |
执行效率 | 最慢 | 最快 | |
适用场景 | 少量的字符串操作 | 单线程下在字符缓冲区进行大量操作 | 多线程下在字符缓冲区进行大量操作 |
StringJoiner类
StringJoiner是Java8新出的用于处理字符串拼接的工具类。
评论区