方法(函数)的参数传递方式一共有两种,分别是值传递和引用传递:

  1. 值传递:

方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。

2引用传递:

也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。

在Java中只有值传递,没有引用传递。比如下面的例子:

public static void add(int i){
        i = 2;
    }

在main方法中调用:

int i = 1 ;
    add(i);
    System.out.println("i = " + i);

控制台输出:

java 传递一个函数 java函数值传递_java 传递一个函数

 

结果是并没有改变,所以显而易见,调用add这个方法,传入的是i的copy,在add中对i进行任何操作都不会影响原本的值。

 

那么可能会有人问,为什么下面的例子就改变了原本的值呢?

Man类:

public class Man {

    private String name;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

修改名字的方法:

public static void  updName(Man man ){
        man.setName("小鹏");
    }

在main方法中调用:

Man man = new Man();
    man.setName("小明");
    System.out.println("调用函数之前的名字:" + man.getName());
    updName(man);
    System.out.println("调用函数之后的名字:" + man.getName());

控制台输出:

java 传递一个函数 java函数值传递_赋值_02

调用函数之前的名字是小明,调用之后就变成了小鹏,这不是改变了原来的值了吗?

其实这里是陷入了一个思想误区,想弄清楚这个问题,首先要明白对象是什么?

简单来说,对象就是对一块内存区域的引用,而这块内存区域其实就是对象真正的值。

在通过Man man = new Man()创建对象的时候JVM都做了哪些操作?

简单来说对象在被创建的时候,编译器会在栈中为Man man 划分一块区域,然后会在堆中为对象的主体划分一块内存区域,并将该内存地址的引用返回给man。这样就可以通过man中存储的地址引用找到该对象真正的内存区域。

(之前写过一个介绍对象的帖子,有兴趣可以看看 传送门)

明白了这个原理之后,就可以将上面的例子形象化一下:

对象指向的内存区域相当于一个密码箱,而对象本身man就是这个箱子的钥匙。在执行updName(man)方法的时候,其实就相当于你复制了一把钥匙,用来打开这个密码箱。因为打开的是同一个箱子,所以这个时候你把箱子里面的水杯替换成笔记本之后,用原配的钥匙(man)再打开箱子的时候,里面的东西一定变成了笔记本,因为你改变的是内存区域里存储的内容,而不是钥匙。

那么相对应的,如果你在复制而来的钥匙上刻下你的名字,会影响原配钥匙(man)吗?当然不会,因为这是两个不同的钥匙!

比如下面这个例子:

方法:

/**
     * 对象重赋值
     * */
    public static void updObj(Man man){
        System.out.println("方法中重赋值前的名字:" + man.getName());
        System.out.println("方法中重赋值前的对象地址:" + man.toString());
        man = new Man();
        System.out.println("重新赋值后的名字:" + man.getName());
        System.out.println("重新赋值后的对象地址:" + man.toString());
    }

 

方法调用:

man.setName("小明");
    System.out.println("调用方法之前的名字:" + man.getName());
    System.out.println("调用方法之前的对象地址:" + man.toString());
    updObj(man);
    System.out.println("调用方法之后的名字:" + man.getName());
    System.out.println("调用方法之后的对象地址:" + man.toString());

 

控制台打印结果:

java 传递一个函数 java函数值传递_Java_03

这里就能很明显的看出来,重赋值之后,对象指向的内存区域发生了改变(也就是换了一个箱子),不管你在方法中怎么对重赋值后的对象操作,对原本对象以及对象中的内容是没有任何改变的(往新箱子里放东西不会影响旧箱子)。

也就是说方法中操作的其实是该对象的copy,并不是其本身。这就验证了Java中是没有引用传递的,只有值传递。

如果我写的不够简单明了,请留评,我及时修改。