按值调用表示方法接收的是调用者提供的值。
引用调用表示方法接收的是调用者提供的变量地址。
方法可以修改按引用传递的变量的值,而不能修改按值传递的变量的值。
Java总是采用按值调用,也就是说方法不能修改传递给它的任何参数变量的内容。

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

然后调用这个方法:

double number = 10;
tripleValue(number);

此时我们的number依旧是10,下面看一下具体的执行过程:

  • x初始化为number值的一个副本。
  • x乘以3后等于30,但是number还是10
  • 方法结束之后,参数变量x不再使用。

这表明Java方法不能修改基本数据类型的参数,但是对象类型的参数我们可以进行修改。
例如讲一个员工的工资增长三倍:

class Employee{
	private String name;
	private double salary;
	
	public void raiseSalary(double byPercent){
		double raise = salary * byPercent / 100;
		salary += raise;
	}
	 public static void tripleSalary(Employee x){
		x.raiseSalary(200);
	}
	//省略其它方法及属性
}

当我们调用

harry = new Employee(...);
tripleSalary(harry);

具体执行过程为::

  • x初始化为harry值得一个副本,这里就是一个对象引用。
  • raiseSalary方法应用于这个对象引用。x和harry同时引用的那个Employee对象的工资提高了200%。
  • 方法结束后,参数变量x不再使用。当然,对象变量harry继续引用那个工资增长三倍的员工对象。

所以改变对象参数状态是完全可以的,原因就是方法得到的是对象引用的副本,原来的对象引用和这个副本都引用同一个对象。所以导致有些程序员认为Java对对象采用的是按引用调用,实际上这是不对的。
我们来编写一个交换两个Employee对象的方法:

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

如果Java对对象采用的是按引用调用,那这个方法就可以实现交换:

Employee a = new Employee("张三",...);
Employee a = new Employee("李四",...);
swap(a,b);

运行结果a还是张三,b还是李四,因为在方法结束时参数变量x和y都被丢弃了。变量a和变量b仍然引用方法调用之前所引用的对象。
这个过程说明:Java对对象采用的不是按引用调用,实际上,对象引用是按值传递的。
下面总结一下在Java中对方法参数能做什么和不能做什么:

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

参考书籍:《Java核心技术 卷Ⅰ》