龙空技术网

java 核心技术-12版 卷Ⅰ- 4.5 方法参数

CC躺平混吃 111

前言:

眼前同学们对“java函数参数传递的三种方式”大致比较讲究,你们都想要学习一些“java函数参数传递的三种方式”的相关资讯。那么小编也在网摘上收集了一些有关“java函数参数传递的三种方式””的相关文章,希望大家能喜欢,大家一起来了解一下吧!

原文

首先来回顾在程序设计语言中关于如何将参数传递到方法(或函数)的一些专业术语。按值调用(call by value)表示方法接受的是调用者提供的值。而按引用调用(call by reference)表示方法接受的是调用者提供的变量位置(location)。所以,方法可以修改按引用传递的变量的值,而不能修改按值传递的变量的值。“按……调用”(call by)是一个表中的计算机科学术语,用来描述各种程序设计语言(不只是Java)中方法参数的行为(事实上,以前还有一种按名称调用(call by name),Algol程序设计语言是最古老的高级语言之一,它就采用了按名称调用方式。不过,这种传递方式已经成为历史)。

Java程序设计语言总是采用按值调用。也就是说,方法会得到所有参数值的一个副本。具体来讲方法不能修改传递给他的任何参数变量的内容。

例如,考虑下面的调用:

double percent = 10;

harry.raiseSalary(percent);

不论这个方法具体如何实现,我们知道,在这个方法调用之后,percent 的值还是10.

下面再仔细研究一下这种情况。假定一个方法师徒将一个参数值增加至3倍:

public static void tripleValue(double x) // dont work{	x = 3* x;}

然后调用这个方法:

double percent =10;

tripleValue(percent);

不过,这并不起作用。调用这个方法之后,percent 还是10.下面来看发生了什么:

x 初始化为percent 值的一个副本(也就是10)。x 乘以3 后等于30,但是percent 还是10。如图所示这个方法结束之后,参数变量x 不再使用。不过有两种不同类型的方法参数:基本数据类型(数字、布尔值)对象引用。

你已经看到,一个方法不可能修改基本数据类型的参数,而对象参数就不同了,可以很容易地实现一个方法将一个员工的工资增至3倍:

public static void tripleSalary(Employee x) // work{	x.raiseSalary(200);}

如下调用这个方法时,

harry=new Employee(...);

tripleSalary(harry);

具体的执行过程为:

x 初始化为harry值的一个部分,这里就是一个对象引用。raiseSalary 方法应用于这个对象引用。x和harry 同时引用那个Employee 对象的工资提高了200%。方法结束后,参数变量x 不再使用。当然,对象变量harry 继续引用那个工资增至3倍的员工对象(如图4-7 所示)。

可以看到,实现方法改变对象参数的状态是完全可以的,实际上也相当常见。理由很简单,方法得到的是对象引用的副本,原来的对象引用和这个副本都引用同一个对象。

很多程序设计语言(特别是C++和Pascal)提供了两种参数传递方式:按值调用和按引用调用。有些程序员(甚至有些书的作者)声称Java对的你想采用的是按引用调用,实际上,这是不对的。由于这种误解很常见,所以很有必要给出一个反例来详细地说明这个问题。

下面来编写一个交换两个Employee对象的方法:

public static void swap(Employee x,Employee y){	Employee tmp = x;  x = y;  y = tmp;}

如果Java对对象采用的是按引用调用,那么这个方法就应该能够实现交换:

        var a = new Employee(1);        var b = new Employee(2);        swap(a,b);

但是,这个方法并没有改变存储在变量a和b中的对象引用。swap方法的参数x和y的初始化为两个对象引用的副本,这个方法交换的是这两个副本。

最终,白费力气。方法结束时,参数变量x和y被丢弃了。原来的变量a 和 b仍然引用这个方法调用之前所引用的对象(如下图所示)。

这说明:Java程序设计语言对对象采用的不是按引用调用。实际上,对象引用(object reference)是按值传递的。

下面来总结再Java中对方法参数能做什么和不能做什么:

方法不能修改基本数据类型的参数(即数值型或布尔型)方法可以改变对象参数的状态。方法不能让一个对象参数引用一个新对象。

程序清单4-4 中的程序展示了这几点。在这个程序中,首先试图将一个数值参数的值增至3倍,但没有成功:

Testing tripleValue:

Before : percent = 10.0

End of method : x= 30.0

After : percent = 10.0

随后,成功地将一个员工的工资增至3倍:

Testing tripleSalary:

Before : salary = 50000

End of method : salary = 150000.0

After: salary = 150000.0

方法结束之后,harry 引用的对象的状态发生了改变。这是因为这个方法可以通过对象引用的副本修改所引用对象的状态。

最后,程序演示了方法的失败结果:

Testing swap:

Before : a = Employee#1, b =Employee#2

End of method : x= Employee#2, y =Employee#1

After: a = Employee#1, b =Employee#2

可以看出,参数 x 和y 交换了,但是变量a 和b 没有受到影响。

程序清单4-4 ParamTest.java

/** * This program demonstrates parameter passing in Java. * @version 1.01 2018-04-10 * @author Cay Horstmann */public class ParamTest{   public static void main(String[] args)   {      /*       * Test 1: Methods can't modify numeric parameters       */      System.out.println("Testing tripleValue:");      double percent = 10;      System.out.println("Before: percent=" + percent);      tripleValue(percent);      System.out.println("After: percent=" + percent);      /*       * Test 2: Methods can change the state of object parameters       */      System.out.println("\nTesting tripleSalary:");      var harry = new Employee("Harry", 50000);      System.out.println("Before: salary=" + harry.getSalary());      tripleSalary(harry);      System.out.println("After: salary=" + harry.getSalary());      /*       * Test 3: Methods can't attach new objects to object parameters       */      System.out.println("\nTesting swap:");      var a = new Employee("Alice", 70000);      var b = new Employee("Bob", 60000);      System.out.println("Before: a=" + a.getName());      System.out.println("Before: b=" + b.getName());      swap(a, b);      System.out.println("After: a=" + a.getName());      System.out.println("After: b=" + b.getName());   }   public static void tripleValue(double x) // doesn't work   {      x = 3 * x;      System.out.println("End of method: x=" + x);   }   public static void tripleSalary(Employee x) // works   {      x.raiseSalary(200);      System.out.println("End of method: salary=" + x.getSalary());   }   public static void swap(Employee x, Employee y)   {      Employee temp = x;      x = y;      y = temp;      System.out.println("End of method: x=" + x.getName());      System.out.println("End of method: y=" + y.getName());   }}class Employee // simplified Employee class{   private String name;   private double salary;   public Employee(String n, double s)   {      name = n;      salary = s;   }   public String getName()   {      return name;   }   public double getSalary()   {      return salary;   }   public void raiseSalary(double byPercent)   {      double raise = salary * byPercent / 100;      salary += raise;   }}

标签: #java函数参数传递的三种方式