java--String为啥是不可变的

        首先看一个java程序员应该都知道的一段代码:

public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s1 = "abc";
		String s2 = "abc";
                String s3 = new String("abc");
		System.out.println(s1 == s2 + "" + s1 == s3);
	}

 结果很简单,是true和false。这是因为s1和s2,指向jvm的方法区中同一个字符串“abc”,而s3指向了堆内存中的字符串“abc”。

      字符串是java中最常用的一个数据结构,所以他非常非常重要,重要到怎么强调都不过分的地步。。 因为他用的实在是太多了,所以java的作者创建了一个String类型的常量池,String pool存在的必要条件就是String是不可变的。想象一下如果String可变会发生什么。。  上面的代码如果s2 = “ab”,然后s1发现自己也变了,这肯定是不合理的。所以String是不可变的第一个作用,就是让String pool存在。String 常量池的作用是什么?  让String的使用变得更加简单和高效。举个简单的例子,”abc“这个字符串第一次创建的时候会加入到常量池中,以后在创建字符串”abc“,再也不会新建对象了,直接将引用引到常量池里面就行了。想想平时代码里重复率最高的类型是什么?   这能省下很多内存,也能够让String的使用更简单高效。

        如果字符串是可变的,那会有很多线程问题需要解决,字符串的使用要考虑多线程。 你哪段程序不用String?  如果全部考虑多线程的话,编码的复杂度会增加不少,java的魅力应该也会大打折扣。

        在String类里,有一个private int hash;是用来缓存String的hash值的。这意味着String类型作为hashMap的key,是不用再去计算hash值了,当然他的前提是String不可变,这也是为了更高效的使用String。

       网上流传着一种说法:在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞。   可能是我没到那个高度,我特别不明白的是:  既然黑客可以改变字符串指向的对象的值,他为什么不可以改变字符串指向的对象呢?我一直觉得安全不是作者把字符串设定成final的主要目的。因为即使String不是final的,java也是有很多很多方法来保证安全的。

        我更倾向于这种说法: String是final的,说明他不可被继承。如果String可以被继承会怎么样?  比如说我给你发一个ip,String类型的,那我发我继承自String的mystring当然也可以了。如果你接收到了我的ip并且接受了,但是在你使用的时候我内部代码把ip改了,改成了一个木马网站,那是不是就。。。。

        个人感受:

        就像鲁迅先生的文章一样,也许鲁迅先生只是很简单的写了句话,结果被各种语文老师发挥想象力,变成了各种版本的为理想为祖国。。。。   我一直觉得不管是写代码,还是学别的什么东西,要有自己的理解。。  别人的经验或者技术当然应该学习,但是应该理解成自己的东西。对于不理解的东西,我宁可不要。。  甚至有时候我会觉得作者可能就是为了让java中的String操作起来更像基本类型一样,因为他跟基本类型太像了。。。

        总结一下自己的看法:

        首先,最重要的原因是String太重要了,使用太频繁了,绝对是java代码里面使用最多的类,所以他的效率很重要。所以james Gosling在设计String的时候,用了String常量池来缓存使用到的String,这样多个相同的String在内存中只用保存一份即可,而且创建更高效。

        还是因为String使用太频繁了,而且太重要了,如果每次使用String都要考虑多线程的话,增加编码复杂度,而且也间接得降低了多线程情况下的安全性。

        还是因为String太重要了,因为很多java的核心功能都是用String做参数。如果有别有用心的人继承String然后调用这些api,那java的安全性就得不到保证了。。

       我的水平,暂时只能理解这么多了。。   肯定还有别的原因,以后发现理解了再来更新吧

猜你喜欢

转载自709002341.iteye.com/blog/2269607