String 被声明为 final,因此它不可被继承。
内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
Strng pool就是String 池。也就是内存的数据段区,专门存放静态变量和字符串的区。String a="abc";那么"abc"放在String pool
如果是String a=new String (“abc”); 就放在内存的heap(堆)里。
String s1=new String("test");//创建2个对象,一个Class和一个堆里面
String s2="test";//创建1个对象,s2指向pool里面的"test"对象
String s3="test";//创建0个对象,指向s2指想pool里面的那个对象
String s4=s2;//创建0个对象,指向s2,s3指想pool里面的那个对象
String s5=new String("test");//创建1个对象在堆里面,注意,与s1没关系
System.out.println(s2=="test");//true s2=="test"很明显true
System.out.println(s2==s3);//true,因为指向的都是pool里面的那个"test"
System.out.println(s2==s4);//true,同上,那么s3和s4...:)
System.out.println(s1==s5);//false,很明显,false
System.out.println(s1==s2);//false,指向的对象不一样,
System.out.println(s1=="test");//false,难道s1!="tset"?
使用 String.intern() 可以保证相同内容的字符串变量引用相同的内存对象。
下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同对象,而 s3 是通过 s1.intern() 方法取得一个对象引用,这个方法首先把 s1 引用的对象放到 String Pool(字符串常量池)中,然后返回这个对象引用。因此 s3 和 s1 引用的是同一个字符串常量池的对象。
String s1 = new String("aaa"); String s2 = new String("aaa"); System.out.println(s1 == s2); // false String s3 = s1.intern(); System.out.println(s1.intern() == s3); // true
如果是采用 "bbb" 这种使用双引号的形式创建字符串实例,会自动地将新建的对象放入 String Pool 中。
String s4 = "bbb"; String s5 = "bbb"; System.out.println(s4 == s5); // tru
String, StringBuffer and StringBuilder
1. 可变性
- String 不可变
- StringBuffer 和 StringBuilder 可变
2. 线程安全
- String 不可变,因此是线程安全的
- StringBuilder 不是线程安全的
- StringBuffer 是线程安全的,内部使用 synchronized 来同步