半夜思考,为什么 String 具有不变性

学习 Java 的数据类型时,特殊关照了 String 类型,具有不变性。

当时没有深入思考为什么 String 有不变性。而且我只碰到了 String 才有不变性。Java这样设计的缘由何在。

      突然在想,为什么 Struts2 中的 action 的返回值为什么也是 String 类型的,不是其他类型,SpringMVC中 handle 也是返回的是 String 类型【ModelAndView 里面也包含了视图名的字符串形式,void就不提了,处理 AJAX 】。

    

      下面就好好分析这个字符串不变性。

所谓不变性就是一旦创建一个字符串对象,这个字符串对象的内容就不会被改变了。比如:

package com.msym.test;

public class Test {
    public void show() {
        String str1 = "aaa";
        String str2 = "aaa";
        String str3 = new String("aaa");
        System.out.println("str1的hashCode: " + str1.hashCode());
        System.out.println("str2的hashCode: " + str2.hashCode());
        System.out.println("str3的hashCode: " + str3.hashCode());
        
        str1 = "aaa" + "b";
        System.out.println("str1的hashCode: " + str1.hashCode());
        System.out.println("str2的hashCode: " + str2.hashCode());
    }
    @org.junit.Test
    public void test(){
        show();
    }
}

image

打印出来的结果说明,str1,str2,str3是指向同一块内存空间的,当修改了 str1时,就创建了一个新的字符串了。

上面创建 str1,str2,str3:

        创建 str1 时,常量池里面肯定是没有常量“aaa”,所以会创建出一个,但是当创建 str2时,因为之前已经创建过  “aaa”了,所以会直接指向这个“aaa”;创建 str3 时,尽管使用了 new 关键字,但是还是会先去常量池去搜寻“aaa”,如果存在,就只在堆内存中开辟一段空间,用以存放常量池中“aaa”的地址,如果不存在,那么就先在常量池中创建“aaa”,然后在堆中开辟空间,存储常量池中“aaa”的地址。

下面画张图来说明:【其中的 0X1122 是常量池中“aaa”的地址头,】

image

      而且 String 类的任何方法都不是去修改字符串的值,而是创建了一个新的字符串,原来的字符串如果没有被引用的话,会在一段时间内被 gc 掉,这样貌似看来,这个不变性并没有带来什么好处,反倒浪费了不少内存,但是这样的机制正好有了安全性,只要创建出一个 String 对象,只要他没有被 gc ,任何方法来读取这个对象都会是同一个,不会出现两个一样的,这也是为什么 String 类型在网络连接,数据传递,以及各大框架使用的这么频繁。

 

当然,如果只是想使用 String类的功能,有更好的选择,那就是线程安全的 StringBuffer和线程不安全的StringBuilder。

 

 

 

 

 

 

 

 

 

 

 

1

posted @ 2017-07-02 23:52  码上猿梦  阅读(413)  评论(0编辑  收藏  举报