String/StringBuilder/StringBuffer的区别
可变性
String
类中使用final关键字修饰字符数组来保存字符串。private final char value[]
,所以String对象是不可变的。
StringBuilder
与 StringBuffer
都继承自 AbstractStringBuilder
类。
在 AbstractStringBuilder
中也是使用字符数组保存字符串 char[] value
,但是没有用final关键字修饰,所以这两个对象是可变的。
线程安全性
String
中的对象是不可变的,也可以理解为常量,线程安全。AbstractStringBuilder
是 StringBuilder
与 StringBuffer
的公共父类,定义了一些字符串的基础操作,比如 expandCapacity
、 append
、 insert
、 indexOf
等公共方法。StringBuffer
对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder
并没有对方法进行加同步锁,所以是非线程安全的。
性能
每次对 String
类型进行改变的时候,都会生成一个新的String对象,然后指针指向新的String对象。StringBuffer
每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。
相同情况下, StringBuilder
相比使用 StringBuffer
仅能获得10%~15%左右的性能提升,但却要冒着多线程不安全的风险。
总结
1、操作少量的数据,适用 String
2、单线程操作字符串缓冲区下操作大量数据:使用 StringBuilder
3、多线程操作字符串缓冲区下操作大量数据:使用 StringBuffer
String info = new String("xyz");
创建了多少String对象?
两个。
一个是字面量的 xyz
存放在字符串常量池(1.7后移到堆内存里,原先是在方法区)里,一个是通过 new String()
创建的存放在堆内存当中。
解释:Java为了避免产生大量的String 对象,设计了一个字符串常量池。工作原理是,当创建一个字符串时,JVM首先会检查字符串常量池中是否有值相等的字符串,如果有,则不再创建,直接返回该字符串的引用地址,若没有,则创建,然后放到字符串常量池里,并返回新创建的字符串的引用地址。new String()
,是会在堆内存(不是在字符串常量池)上创建一个新的String对象。
所以, new String('xyz')
,是现在字符串常量池里查找是否有 xyz
的字符串,如果有,则直接引用,如果没有,就创建,然后放在常量池中。当new String时,就会在堆内存中创建一个新的String对象,存储 xyz
,并将内存上的String对象引用地址返回。
扩展:
public class test1 {
public static void main(String[] args) {
String a = new String("ab"); // a 为一个引用
String b = new String("ab"); // b为另一个引用,对象的内容一样
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 从常量池中查找
if (aa == bb) // true
System.out.println("aa==bb");
if (a == b) // false,非同一对象
System.out.println("a==b");
if (a.equals(b)) // true
System.out.println("aEQb");
if (42 == 42.0) { // true
System.out.println("true");
}
}
}