乐趣区

String是值传递还是引用传递

String 中的坑

  最近看到一道关于 String 的面试题,差点让我以为 String 是值传递,就是下面这个例子,体验下:<!– more –>

public class Demo{public static void main(String[] args) {Demo d = new Demo();
        String str = "BEA";
        d.change(str);
        System.out.println(str);
    }
    void change(String s){s= s.replace('A', 'E');
        s = s.toLowerCase();}
}

  当时一看到这个题目,我第一反应就是输出”bee“,因为 String 是引用类型,其参数传递的方式就是引用传递,传递的是 String 的地址。可是答案让我的大吃一惊,“BEA”,str 根本就没有发生变化!!

  难道 String 是值传递?难道 String 是基本类型?

  其实都不是,后来通过查阅相应资料发现,jvm 在实例化字符串时会使用字符串常量池,把 str 作为参数传入 change()方法。jvm 复制了一份 str 变量,为了便于理解我们叫它 str’。这个时候 str 和 str’ 都指向字符串常量池中的“abc”。

  当我们执行 s = s.replace('A', 'E');
其实相当于执行了s = new String(s.replace('A', 'E'));

 要理解上面这两段话,就要从 java 的底层结构说起了。java 的内存模型大体分为 (细分还有方法区,和程序计数器等)。

1. 基本类型的变量放在栈里;

2. 封装类型中,对象放在堆里,对象的引用放在栈里。

<font color=red>java 在方法传递参数时,是将变量复制一份,然后传入方法体去执行。</font>

根据这些再细分一下 jvm 的执行过程

1. 虚拟机在堆中开辟一块内存,并存值”BEA”。

2. 虚拟机在栈中分配给 str 一个内存,内存中存的是 1 中的地址。(1 指第一步)

3. 虚拟机复制一份 str,我们叫 str’,str 和 str’内存不同,但存的值都是 1 的地址。

4. 将 str’传入方法体

5. 方法体在堆中开辟一块内存,并存值”BEE”。

6. 方法体在堆中再次开辟一块内存,并存值”bee”。

7. 方法体将 str’的值改变,存入 5 的内存地址。

8. 方法结束,方法外打印 str,由于 str 存的是 1 的地址,所有打印结果是”BEA”。

 String 的底层是一个不可变数据,所以每次给他赋新的值的时候都相当于新建了一个 String 对象(如果 String 常量池里没有该字符串的话),我们可以验证一下。

public class Demo{public static void main(String[] args) {Demo d = new Demo();
        // 通过比较 str 的 hashCode 来比较两个对象是否为同一对象
        String str = "BEA";
        System.out.println("第一次 String 的 hashCode:"+str.hashCode());
        str = "bee";
        System.out.println("第二次 String 的 hashCode:"+str.hashCode());
        //StringBuilder 来试一次
        StringBuilder s = new StringBuilder("BEA");
        System.out.println("第一次 StringBuilder 的 hashCode:"+s.hashCode());
        s.append('T');
        System.out.println("第二次 StringBuilder 的 hashCode:"+s.hashCode());
        System.out.println("调用方法前的 StringBuilder 对象的值:"+s);
        d.change(s);
        System.out.println("调用方法后的 StringBuilder 对象的值:"+s);
    }
    void change(StringBuilder s){s = s.append('S');
    }
}

  看看执行的结果~

tips: hashcode 并不能判断是否为同一个对象,但是 hashcode 不同的话肯定不是同一个对象,hashcode 相同的不一定是同一个对象。

关注我不会让你失望哟~

退出移动版