String,StringBuffer, StringBuilder 的区别是什么?String为何是不可变的?

本内容是我从各处转载整理得来,是个人学习笔记,若有涉及到版权问题,请给我留言。javascript

或者内容中有不正确的地方,也请各位大神能帮我指出更改,谢谢!java

 

1、区别面试

一、String是字符串常量,而StringBuffer和StringBuilder是字符串变量。由String建立的字符内容是不可改变的,而由StringBuffer和StringBuidler建立的字符内容是能够改变的。sql

二、StringBuffer是线程安全的,而StringBuilder是非线程安全的。StringBuilder是从JDK 5开始,为StringBuffer类补充的一个单线程的等价类。咱们在使用时应优先考虑使用StringBuilder,由于它支持StringBuffer的全部操做,可是由于它不执行同步,不会有线程安全带来额外的系统消耗,因此速度更快。数据库

 

2、String为何不可变编程

虽然String、StringBuffer和StringBuilder都是final类,它们生成的对象都是不可变的,并且它们内部也都是靠char数组实现的,可是不一样之处在于,String类中定义的char数组是final的,而StringBuffer和StringBuilder都是继承自AbstractStringBuilder类,它们的内部实现都是靠这个父类完成的,而这个父类中定义的char数组只是一个普通是私有变量,能够用append追加。由于AbstractStringBuilder实现了Appendable接口。数组

 

3、为何String要设计成不可变缓存

 

在Java中将String设计成不可变的是综合考虑到各类因素的结果,想要理解这个问题,须要综合内存,同步,数据结构以及安全等方面的考虑. 在下文中,我将为各类缘由作一个小结。安全

1. 字符串常量池的须要性能优化

字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当建立一个String对象时,假如此字符串值已经存在于常量池中,则不会建立一个新的对象,而是引用已经存在的对象。

以下面的代码所示,将会在堆内存中只建立一个实际String对象.

 

[java] view plaincopy

  1. String s1 = "abcd";  
  2. String s2 = "abcd";  

示意图以下所示:

 

图1

 

倘若字符串对象容许改变,那么将会致使各类逻辑错误,好比改变一个对象会影响到另外一个独立对象. 严格来讲,这种常量池的思想,是一种优化手段.

思考: 倘若代码以下所示,s1和s2还会指向同一个实际的String对象吗?

 

[javascript] view plaincopy

  1. String s1= "ab" + "cd";  
  2. String s2= "abc" + "d";  

也许这个问题违反新手的直觉, 可是考虑到现代编译器会进行常规的优化, 因此他们都会指向常量池中的同一个对象. 或者,你能够用 jd-gui 之类的工具查看一下编译后的class文件.

 

2. 容许String对象缓存HashCode
Java中String对象的哈希码被频繁地使用, 好比在hashMap 等容器中。

字符串不变性保证了hash码的惟一性,所以能够放心地进行缓存.这也是一种性能优化手段,意味着没必要每次都去计算新的哈希码. 在String类的定义中有以下代码:

 

[javascript] view plaincopy

  1. private int hash;//用来缓存HashCode  

3. 安全性
String被许多的Java类(库)用来当作参数,例如 网络链接地址URL,文件路径path,还有反射机制所须要的String参数等, 倘若String不是固定不变的,将会引发各类安全隐患。

 

假若有以下的代码:

 

[javascript] view plaincopy

  1. boolean connect(string s){  
  2.     if (!isSecure(s)) {   
  3. throw new SecurityException();   
  4. }  
  5.     // 若是在其余地方能够修改String,那么此处就会引发各类预料不到的问题/错误   
  6.     causeProblem(s);  
  7. }  

 

 

整体来讲, String不可变的缘由包括 设计考虑,效率优化问题,以及安全性这三大方面. 事实上,这也是Java面试中的许多 "为何" 的答案。

 

4、String类不可变性的好处

 

String是全部语言中最经常使用的一个类。咱们知道在Java中,String是不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。

String类不可变性的好处

1.只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现能够在运行时节约不少heap空间,由于不一样的字符串变量都指向池中的同一个字符串。但若是字符串是可变的,那么String interning将不能实现(译者注:String interning是指对不一样的字符串仅仅只保存一个,即不会保存多个相同的字符串。),由于这样的话,若是变量改变了它的值,那么其它指向这个值的变量的值也会一块儿改变。 2.若是字符串是可变的,那么会引发很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来得到数据库的链接,或者在socket编程中,主机名和端口都是以字符串的形式传入。由于字符串是不可变的,因此它的值是不可改变的,不然黑客们能够钻到空子,改变字符串指向的对象的值,形成安全漏洞。 3.由于字符串是不可变的,因此是多线程安全的,同一个字符串实例能够被多个线程共享。这样便不用由于线程安全问题而使用同步。字符串本身即是线程安全的。 4.类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改为了myhacked.Connection,那么会对你的数据库形成不可知的破坏。 5.由于字符串是不可变的,因此在它建立的时候hashcode就被缓存了,不须要从新计算。这就使得字符串很适合做为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键每每都使用字符串。

相关文章
相关标签/搜索