目录
1.StringBuilder
相比于字符串进行拼接等操作,更方便快捷
StringBuilder sb = new StringBuilder();
//可以空参&有参构造
//常用方法
sb.append();
sb.reverse();
String str = sb.toString();
sb.length(); //查看长度
sb.capacity(); //查看容量
StringBuilder存储原理分析:
- 默认创建一个长度为16的字节数组
- 添加的内容长度小于16,直接存入数组中
- 添加的内容大于16会扩容(原来的容量*2+2=34)
- 如果扩容之后还不够,以实际长度为准,长度为多少就扩容为多少
2.字符串常量池(串池)
字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最常用的数据类型之一,大量频繁的创建字符串对象,极大程度地影响程序的性能,所以JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化:
- 为字符串在堆区开辟一个字符串常量池,类似于缓存区
- 创建字符串常量时,首先查找字符串常量池是否存在该字符串
- 存在该字符串,返回引用实例(串池地址),不存在,实例化该字符串并放入池中
实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突,而且运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。
3.字符串拼接的底层原理
首先要分为两种情况,拼接等号右边没有变量/有变量,如下代码,
String s = "a" + "b" + "c";
//没有变量
String s1 = "a" + "b";
Sreing s2 = s1 + "c";
//有变量
如果拼接的时候有变量就会复杂一些,JVM会自动生成一个StringBuilder在堆内存中,然后执行相关操作:执行new String(“字符串1”) + new String(“字符串2”),会创建StringBuilder对象,并将字符串1和字符串2的内容追加其中,然后调用StringBuilder对象的toString()方法,将其转换为一个新的字符串对象,内容为”字符串1字符串2“,这个新的字符串存储在堆上。
也就是说,当编译器遇到 + 号这个操作符的时候,会将 new String(“s1”) + new String(“s2”) 这行代码编译为以下代码:
new StringBuilder().append("字符串1").append("字符串2).toString();
所以说,字符串拼接时如果直接用“+”的话,非常浪费时间和空间,底层原理仍然是StringBuilder,那不如直接用StringBuilder一步到位。
String是字符串类,属于引用数据类型。
总结:
- 字符串存储的内存原理:直接赋值会复用字符串常量池中,new的新出来不会复用,而是开辟一个新的空间
- ==号比较的到底是什么?:基本数据类型比较数据值,引用数据类型比较地址值
- 字符串拼接的底层原理:如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用串池中的字符串;
如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存。 - 所以说如果要拼接字符串,最好用StringBuilder类,不会创建很多无用的空间,全程就只有一个StringBuilder。
4.ArrayList集合
//创建方式
ArrayList<String> list = new ArrayList<>();
集合和数组的区别:
长度 | 存储类型 | |
数组 | 不可变 | 基本/引用 |
集合 | 可变 | 引用数据类型 |