NO.1 方法参数按“值”而非按“引用”方式传递 | Java敲黑板系列

图1

基本概念

方法(也称函数)调用是程序设计语言一种最基本的功能。一个完整的方法声明一般包括了返回值、方法名称、方法参数三个基本要素,俗称“三朵金花”。今天我们主要来谈谈这金兰三姐妹中的幺妹——方法参数。

方法被调用其中有一个重要的过程,就是对三妹进行虚实结合,也称形参与实参相结合,平时三妹就是一个符号,发生方法调用时,调用方会把实际的参数传递给方法。传递的方式分为两种:按值调用与按引用调用

按值调用:表示方法接收的是调用者提供的值
按引用调用:表示方法接收的是调用者提供的变量地址

上述两者最大的区别在于,前者不能修改传递值所对应的变量值;后再可以修改传递引用所对应的变量值。是不是有点绕?没有关系,现在只需要记住上述两种方式几乎涵盖了所有编程语言中方法参数的传递方式。此外,最为重要的是:Java语言使用了按值调用的方法参数的传递方式

案例分析

以下案例主要是为了说明其思想,采用了伪代码形式。

案例1

public static changeCircle(Point center, int radius){
      center.setLocation(10,10);
      radius = 100;
      System.out.println("In changeCircle. center is: " + center + "; radius is : " + radius);
}

static void main(String[] args){
      Point pt = new Point(0,0);
      int r  = 5;
      changeCircle(pt, r);
      System.out.println("After changeCircle. center is: " + pt + "; radius is : " + r);
}

答案:
In changeCircle. center is : (10,10); radius is : 100
After changeCircle. center is: (10,10);radius is : 5

解析:
执行完成后 ,可以发现pt变量的值发生了变化,r变量的值没有发生变化。为什么?开始敲黑板:Java语言使用了按值调用的方法参数的传递方式。我们下面用这个原则来分别进行解释:

(1)首先分析变量r。首先变量r是“基本数据类型”,在进行虚实结合的时候,发生了以下的事情:

  • 方法changeCircle中的变量radius会用main方法的变量r的拷贝值进行初始化;
  • 此后,在方法changeCircle中的radius会被更新为100,但是此时的变量r不会发生任何改变;(因为是按值传递)
  • 方法changeCircle结束后radius变量不再有任何用处。详情下图。

图2

(2)然后,我们再来看看变量pt到底发生了什么。首先pt是一个对象参数;类比(1)中的分析,由于Java是通过传值的方式进行传递参数,为此发生方法调用时,变量pt会产生一个副本传递给center变量,由于两个对象变量是不同的对象,为此后续就互不影响。这样对吗?错!其实从程序输出中也可以看出,center变量的修改的确是影响了变量pt的值。这是为什么了?

扫描二维码关注公众号,回复: 1463230 查看本文章

敲黑板:在Java中,如果方法参数是对象类型,那么传递的是对象的引用的复件,而不是对象的复件。两者之间有巨大的差别:对象的引用其实就是对象变量所对应的地址,这就说明发生方法调用时,pt变量的地址通过传值的方式传递给了center变量的地址,让两个变量指向了同一个对象,center成为了pt的别名,为此所有对center变量成员变量的修改都会同样作用于pt身上。为此,我们看到了调用changeCircle后,pt的值发生了变化。同样的,我们分步骤看看到底发生了什么:

  • center被初始化为pt对象的引用,即两个变量的地址相同,都指向了同一个对象(也就是同一块内存区域)
  • 对center对象所有成员变量的进行修改。所有的修改结果都会反馈到pt对象上。因为两者是同一对象,只是名字不一样而已。
  • 方法调用结束后,center变量不再有用。但是所有的修改情况都反映在变量pt上了。详情见下图。

图3

案例2

public static swap(Point p1, Point p2){

      Point temp = p1;

      p1 = p2;

      p2 = temp;

      System.out.println("In swap. p1 is: " + p1 + "; p2 is : " + p2);

}


public static void main(String[] args){

      Point pt1 = new Poin(0,0);

      Point pt2 = new Point(10,10);

      swap(pt1, pt2);

      System.out.println("In main. pt1 is: " + pt1 + "; pt2 is : " + pt2);
}

这算是一个思考题吧,请老铁们想想该程序会输出什么?请在留言区写出你的答案,正确答案会在下篇文章中进行公布。

小结

敲黑板,画重点:

  1. Java语言中的方法参数使用了按值调用的方法。具体来讲,对于基本类型变量采用了值拷贝的方式;对于对象变量采用了对象引用拷贝的方式。
  2. 上述传递方式也不用死记硬背,记下下面的两个例子,就完全理解了。可以把方法调用时方法参数传递方式类比于Java中的赋值操作。
int  val = 5;
int  passVal = val;
//基本类型赋值操作后,val与passVal独立变化,互不影响;
//等同于基本类型的方法参数调用

Point pnt = new Point(5,5);
Point passPnt = pnt; 
//对象类型赋值操作后,两个变量指向了同一个对象。
//在调试器中可以看见两个对象的ID是相同的。
//其中一个变量的成员变化都会同样作用于另外的一个变量
//等同于对象类型的方法参数调用

转载自公众号:代码荣耀
图4

猜你喜欢

转载自blog.csdn.net/maijia0754/article/details/80565627