1、String、StringBuffer、StringBuilder 类关系
String 是不可变的,StringBuffer、StringBuilder是可变的。
2、底层实现
String类的底层实现是static final char[ ] value,也就是说String字符串是存在一个char数据中的,static说明value是类变量,final则规定了value之不可变,StringBuffer 和 StringBuilder 的底层都是char[ ] value数组
3、线程安全
因为String类的字符串值存在常量池不可进行修改,所以认为String类是线程安全的
StringBuffer类是线程安全的,他的方法都是synchronized关键字修饰的
StringBuilder类是线程不安全的
4、执行速度
这三个类在进行操作时的速度关系为:StringBuilder > StringBuffer > String
由于String中进行操作时都会新建一个char[ ]数组代替原来的char[ ]数组,所以速度最慢
StringBuffer线程安全,每个方法都有synchronized同步阻塞,所以操作速度受影响
StringBuilder没有同步阻塞的限制,所以操作速度最快
5、使用场景
如果要操作少量的数据用 = String
单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
6、String 创建对象
String str = "a"+"b"+"c"+"d";
在使用上述方式创建字符串时,每使用“+”号连接一个字符串就会创建一个新的String的对象,这会造成内存极大的浪费
1,例如,创建一个对象
String str = "ch";
此时会在常量池中创建一个ch对象,并且会在栈中创建一个对象的引用str。也就是说这句代码只创建了一个对象。
2,但如果是
String str1 = "ss" + "hh";
就会在栈中创建一个引用str1,在常量池中创建三个对象:ss对象,hh对象,和sshh对象,这是因为,
程序首先会去常量池中寻找是否有ss字符串对象,不存在,则创建ss对象。
hh对象同一个道理
因为字符创属于不可变的对象,所以如果想要获取到sshh对象只能是去在常量池再次创建一个sshh对象
3 如果是使用new创建字符串
String str2 = new String("tt");
首先程序会在堆中创建一个new String对象,因为在new的过程中需要到“tt”,所以会去常量池中去寻找tt对象,如果对象不存在,则要去创建。
所以这句代码是在常量池创建了一个对象:tt,在堆中创建了一个对象new String,在栈中创建了对象的引用str2
4,如果是用StringBuilder:
StringBuilder str3 = "pp";
StringBuilder str4 = str3.append("ll");
程序首先要在常量池中去创建pp这个对象,在append时在常量池中创建ll这个对象,在这里只创建了两个对象,在栈中创建了3个引用。这是因为StringBuilder分配的空间是可变的,所以在append之时,是直接把ll对象添加到pp所在的存储区域中。
以上所有的分析都是假设在创建字符串对象时常量池中不存在对应字符串的情况下得出的结果,如果在常量池中有对应的字符串存在则不再需要创建对象
总结:
对象存在的位置是在堆中(new出来的),常量池中(“”,直接定义出来的)
对象的引用存在栈中