传递与引用

Java中所有函数调用本质上都是值传递。首先我们来看这样一段程序:

public class Test {
        public static void main(String[] args) {
            int i = 10;
            String str = new String("World");
            char[] ch = { 'H', 'e', 'l', 'l', 'o' };
            change(i, str, ch);
            System.out.println(i);
            System.out.println(str);
            ;
            System.out.println(ch);
        }

        public static void change(int i, String str, char[] ch) {
            i = 20;
            str = "Changed";
            ch[0] = 'c';
        }
    }

输出结果为:

10

World

cello


 

       这里涉及到的就是Java传递和引用的问题。Java中所有的函数本质上都是值传递,也就是说函数的形参是实参的一份副本。如果实参是基本类型,那么形参就是基本类型的值的副本;如果实参是引用类型,那么形参就是引用类型的句柄的副本。我们可以把值当做一个仓库,把引用类型句柄当做一把钥匙。这样我们再来看上面的几行代码。

       变量 i 是基本类型,在执行函数 change(int i, String str, char []ch) 时,只是把 i 的值(10)的副本传给了形参中的 i ,可以想象成是在原来的仓库旁边有建了个仓库,往新仓库里放了20袋大米,但是新仓库里的东西和原来放10袋大米的仓库没有关系,所以最终打印的还是原来仓库中的10袋大米。

       接下来先说一下char数组,在执行change 函数的时候,同样是将char数组的句柄传递给形参。上边我们说可以把句柄想象成钥匙,那在这里我们就试试。执行change的时候,我们把钥匙的副本(注意无论是值还是句柄,传递的都是副本)传给了ch,它用这把复制的钥匙一样可以打开原来存放 hello 的仓库,所以它打开了仓库,把 'h' 换成了 'c' ,最终打印的时候我们就看到了 cello 的结果。

       至于String有些同学大概会有疑问,不是说除了四类八种之外都是引用类型么,那么String也是引用类型,那为什么str 的值没有改变呢?

       确实,String属于引用类型,但是让我们来看看String类的一部分定义:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** The offset is the first index of the storage that is used. */
    private final int offset;

    /** The count is the number of characters in the String. */
    private final int count;

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

从Java中String的定义我们可以看出,String类及其成员变量都是final类型,即不能被更改的,这就相当于你拿了配好的钥匙副本但是却搬不动仓库里的东西,什么都动不了,所以在最后打印的时候str 的结果还是 World 不会变。

 

原文地址:https://www.cnblogs.com/yuxiaoqi/p/2710666.html