- String所声明的对象不可改变。在1.7之后,String的主要属性就是valur[],如下图所示,声明为private ,且没有相应的Set方法,所以在String的外部不能够修改String,也就是说一旦初始化之后就不能够改变值,且声明为final,也就是说一旦声明之后,String就是不能改变的了。因为String是不可修改的,所以安全性最高。
- StringBuffe。正是因为String是不可修改的,所以每次修改时,都会新增一个String的对象,所以比较浪费资源,于是就有了StringBuffer的出现,它利用append()方法来实现字符串的改变,且所有方法都加了synchronized关键字,能够保证线程的安全性,但是也相应的性能降下来,于是就有了StringBuilder
- StringBuilder。相对StringBuffer,去掉了关键字,所以性能大大提升,但是不是线程安全的。
- 综上:
- 线程安全性:String>StringBuffer>StringBuffer
- 性能方面:StringBuilder>StringBuffer>String
- 若所使用的字符串改动量不大,或者不经常使用,可以使用String;
- 如需要频繁的更改字符串,在多线程场景下,则可考虑StringBuffer;
- 如需要频繁的更改字符串,在单线程场景下,则可考虑StringBuilder;
- 最后搞个String的小例子:
String s = "ABCabc"; System.out.println("s = " + s); s = "123456"; System.out.println("s = " + s);
结果是:
ABCabc
123
首先创建一个String对象s,然后让s的值为“ABCabc”, 然后又让s的值为“123456”。 从打印结果可以看出,s的值确实改变了。那么怎么还说String对象是不可变的呢? 其实这里存在一个误区: s只是一个String对象的引用,并不是对象本身。对象在内存中是一块内存区,成员变量越多,这块内存区占的空间越大。引用只是一个4字节的数据,里面存放了它所指向的对象的地址,通过这个地址可以访问对象。 也就是说,s只是一个引用,它指向了一个具体的对象,当s=“123456”; 这句代码执行过之后,又创建了一个新的对象“123456”, 而引用s重新指向了这个心的对象,原来的对象“ABCabc”还在内存中存在,并没有改变。内存结构如下图所示
-
再看一段代码:
String b = "qwe"; System.out.println(b); b.replace("w","g"); System.out.println(b);
执行结果
qwe qwe
再次证明了String对象不可修改。不过网上说反射可以进行更改,感兴趣的可以看看。
123456