String/StringBuilder/StringBuffer的区别

可变性

String 类中使用final关键字修饰字符数组来保存字符串。
private final char value[] ,所以String对象是不可变的。

StringBuilderStringBuffer 都继承自 AbstractStringBuilder 类。
AbstractStringBuilder 中也是使用字符数组保存字符串 char[] value ,但是没有用final关键字修饰,所以这两个对象是可变的。

线程安全性

String 中的对象是不可变的,也可以理解为常量,线程安全。
AbstractStringBuilderStringBuilderStringBuffer 的公共父类,定义了一些字符串的基础操作,比如 expandCapacityappendinsertindexOf 等公共方法。
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对象引用地址返回。

扩展:

  1. public class test1 {
  2. public static void main(String[] args) {
  3. String a = new String("ab"); // a 为一个引用
  4. String b = new String("ab"); // b为另一个引用,对象的内容一样
  5. String aa = "ab"; // 放在常量池中
  6. String bb = "ab"; // 从常量池中查找
  7. if (aa == bb) // true
  8. System.out.println("aa==bb");
  9. if (a == b) // false,非同一对象
  10. System.out.println("a==b");
  11. if (a.equals(b)) // true
  12. System.out.println("aEQb");
  13. if (42 == 42.0) { // true
  14. System.out.println("true");
  15. }
  16. }
  17. }