1.一道笔试题

这是一道经典的String面试题,猜猜输出结果是多少?

public class StringTest {
    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) {
        StringTest ex = new StringTest();
        ex.change(ex.str, ex.ch);
        System.out.println(ex.str);
        System.out.println(ex.ch);
    }
​
}

结果是:

good
best

怎么样,有答对吗。为什么是这个结果呢,就关系到了String的不可变性与Java的求值策略。

2.String的不可变性

有了解过Java底层源码的应该都知道,String的存储变量是带final关键字的,这意味的这个字符串是无法被修改的,在它放入堆中字符串常量池(JDK8以后)中后,内存地址以及内容就会被永久确定下来(除非在池中被回收)。

String底层源代码:

// JDK9之前
private final char value[];
// JDK9及之后
private final byte[] value

3.Java值传递的方式

Java的传递很像引用传递(引用传递就是传递自身变量不会拷贝变量副本),但其实是值传递,因为这个传递的过程并不是把原变量传递出去,而是拷贝了原变量的内存地址。

这样说可能非常难懂,我第一次看也是一脸懵*。但是再结合上面的例子看呢。

由于传递的确实是内存地址,但并不是我原本String字符串自身的内存地址,我依然指向我的内存地址。我把内存地址给你了,能不能修改就看你本事了。而Char[]在堆中是没有不可变这个特性的,所以它就会在change(String str, char ch[])方法中被修改了对象数据。

这么理解是不是非常通俗易懂呢?