详解String 对象的不可变性

1.一道关于String和值传递的笔试题

我们先来看看这道关于String和值传递的笔试题,有没有很熟悉,是不是在无数个寂寞的刷题的夜里曾经看到过它,并表示下次再也不想看到它了。因为有的时候怎么也想不通为啥这个值输出是good,小朋友你是否有很多的问号?这其实就是涉及到我们标题所说的String的不可变性。

public class StringTransmit {
    String str = new String("good");
    char [] ch = {'t','e','s','t'};
    public void change(String str,char ch[]){
        str = "test ok";
        ch[0] = 'b';
    }

    public static void main(String[] args) {
        StringTransmit ex = new StringTransmit();
        ex.change(ex.str,ex.ch);
        System.out.println(ex.str);//good
        System.out.println(ex.ch);//test
    }

}

 2.图解过程

这里贴出了一张图解的过程和经过我改过便于说明的代码。把形参str改为str1,便于区分,增加了比较str和str1地址的打印输出。(heapString变量想说明一下String对象存在堆和方法区的问题,简单说下就是,String s1 ="123";这种方式是字面量定义,"123"是放在方法区的字符串常量池(1.8后常量池还是在方法区里面),String s2 = new String("123");,new 出来的String对象是放在堆当中的,但是"123"这个value值它还是存在方法区中,也就是在方法区也创建一个”123“.所以有问题说String s2 = new String("123")创建了几个对象,答案是两个)。 

private final char value[];
public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
public class StringTransmit {
    String str = new String("good");
    char [] ch = {'t','e','s','t'};
    public void change(String str1,char ch[]){
        System.out.println(this.str == str1);//true
        str1 = "test ok";
        System.out.println(this.str == str1);//false

        //String heapString = new String("test ok");
        //System.out.println(str1==heapString);//false
        ch[0] = 'b';
        System.out.println(this.ch==ch);//true
    }

    public static void main(String[] args) {
        StringTransmit ex = new StringTransmit();
        ex.change(ex.str,ex.ch);
        System.out.println(ex.str);//good
        System.out.println(ex.ch);//best
    }

}

回到我们的String不可变的问题,其实从第一个打印语句System.out.println(this.str == str1);//true的结果是true,经过赋值操作之后的第二个打印语句System.out.println(this.str == str1);//false的结果是false,已经是给出了一个线索了,说明什么呢?在经过赋值操作之后,str 成员变量和str1 形参它们的地址值是不一样的,那么str1的修改不是去操作str 指向的地址的对象就可以理解了,因为如果是修改了str 指向的地址值的对象,那么它两的地址值应该是一致的,从结果看,并不是 。

下面说说详细的过程,调用ex.change(ex.str,ex.ch)方法,str 成员变量把存放对象堆中的地址给str1 ,那么当前str 和 str 1指向的对象是一致的。执行str1 = "test ok",此时str1想去修改共同指向的对象的值,然后发现这个对象是不可变的。(String不可变性值的是堆中的String对象或方法区字符串常量池中的对象是不能被改变的)那么怎么办呢,我需要有个地方存放”test ok“这个值,如果是普通的对象,直接在堆中申请一块内存,把new 出来的新对象放在内存当中,然后把”test ok“放进去,最后把str1和新开辟的对象关联上。但是String比较特殊,采用str1 = "test ok"字面量定义的方式,test ok是放在方法区的常量池当中的,然后把方法区中的对象和str1关联起来。但无论是放在堆中和方法区中,因为String对象的不可变性,都是需要新的一块内存区域来存放"test ok",也就是说原先对象的内容不会被改变。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值