最新消息:

java中为什么字符串(String)是不可变或Final的

JAVA 大步 1067浏览 0评论
String在java中是不可变的,因为字符串对象被缓存在String pool(字符串池)中。当缓存的字符串被多个客户端共享的时候就会存在一些风险,可能一个客户端的动作会影响所有其他的客户端。例如,如果一个客户端将字符串“Test”的值改为“TEST”,这样所有其他的客户端将会看到修改后的“TEST”值。当为了性能的原因而缓存字符串对象时,我们可以通过将String类变为不可变来避免这一风险。同时,将String变成final的,这样就没有人会危害String类的不可变性。eg,通过扩展(extending)和覆盖行为来改变其不可变性,缓存,hashcode计算等。String为不可变的另外一个原因是会导致HashMap挂掉。因为字符串经常被用来作为HashMap的key,所以对于它们来说保持不可变是很重要的,这样才能通过键找到HashMap中存储的对应的对象。因为HashMap是通过散列的原理来工作的, 需要有同样的值来保证正确工作。当可变(mutable)字符串的内容在插入之后被修改了,则该字符串可能会在插入和取回的时候,产生两个不同的hashcode,从而可能会丢失map中的保存到对象。

 

java中字符串为什么是final的
原因

 

1:在String pool中,一个字符串可能被多一个引用变量引用,例如“Test”被多个引用变量引用了,所以如果任何引用变量改变了这个字符串的值,则其他的引用变量会自动被印象。如下:

 

String A = "Test"
String B = "Test"

 

现在,字符串B钓鱼那个"Test.toUpperCase()",将“Test”变成“TEST”。则A也会变成“TEST”,这并不是我们期望的。下面的图展示了字符串在堆内存和String literal pool中创建:
file:///E:/CyberfoxPortable41/Data/profile/ScrapBook/data/20160214120104/String+in+Java+is+Immutable.jpg

 

2.字符串广泛的被用来作为java类的参数,例如,打开网络链接,你们能将主机名和端口作为字符串来传递,也可以在打开数据库连接的时候将数据库地址作为字符串来传递,或者是,我们通过传递文件名作为文件I/O类的参数来打开文件。
如果字符串是可变的,这将会导致严重的安全问题,意味着某个人能访问任意文件,只要这个人对这些文件拥有授权,然后他能有意或无意的修改这些文件名并且获得这些文件的访问权限。因为不可变性,你无需担心这种威胁。这也是为何在java中,String也是final的,通过使得java.lang.String类为final,java设计者确保没有人能够覆盖String类的任何行为。

 

3.因为String是不可变的,所以它可以安全的在多个线程间共享。这对于多线程编程来说很重要,能避免java中的任何同步问题。不可变性也使得java中的String实例是线程安全的,这意味着你无需在外部同步字符串操作。另一个重点是字符串容易因为SubString而导致内存年泄漏,这虽然不是线程相关的问题,却也是要注意的。

 

4.另一个原因是不可变性能够允许String去缓存它的hashcode,java中的不可变字符串缓存它们的hashcode,这样我们每次调用String的hashcode方法的时候就无需再次计算hashcode,因此这个特性能够使得在java中将字符串作为hashmap的key时,变得更快。简单来说,因为字符串是不可变的,一旦创建就没有人能够改变它的内容,这样就确保了字符串的hashcode能够在多次调用时,它的hashcode都是相同的。

 

5.字符串是不可变的最重要的原因是String被类加载机制所使用,因此有深刻和基本的安全方面的考虑。加入字符串是可变的,当一个请求加载“java.io.Writer”可能会被修改为加载“mil.vogoon.DiskErasingWriter”。

 

安全和String pool成为使得字符串不可变的主要原因。我相信可能有更多的其他原因,请在评论中告诉我,我将会添加到文章中。顺便说一下,之所以String还是final的,就是为了避免子类破坏其不可变性。
原文地址:《Why String is Immutable or Final in Java

 

来自为知笔记(Wiz)

 

转载请注明:大步's Blog » java中为什么字符串(String)是不可变或Final的

SiteMap