形参 & 实参

参数在程序语言中分为实参和形参:

  • 实际参数:用于传递给函数/方法的参数,必须有确定的值。
  • 形式参数:用于定于函数/方法,接收实参,不需要有确定的值。

值传递 & 引用传递

程序设计语言将实参传递给函数的方法分为两种:

  • 值传递:方法接收的是实参的值的拷贝,会创建副本。
  • 引用传递:方法接收到的是实参所引用的对象在堆中的地址,不会创建副本,意味着修改形参会同时修改实参。

Java 的值传递

Java 中将实参传递给方法/函数的方式是值传递:

  • 如果参数是基本数据类型,传递的是基本类型的字面量值的拷贝,会创建副本。
  • 如果参数是引用类型,传递的是实参所引用的对象在堆中的内存地址的拷贝,同样也会创建副本。

传递基本类型参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 传递基本类型参数
*/
public static void main(String[] args) throws Exception {
int n1 = 10;
int n2 = 20;
swap(n1, n2);
System.out.println("n1 is " + n1);
System.out.println("n2 is " + n2);
}

public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("a is " + a);
System.out.println("b is " + b);
}

/**
* 输出
* a is 20
* b is 10
* n1 is 10
* n2 is 20
*/

在 swap 中 a、b 的值是从 n1、n2 复制过来的,相当于 n1、n2 的副本。所以无论怎么修改交换 a、b 的值,都不会改变 n1、n2 的值。

传递引用类型参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 传递引用类型参数
*/

public static void main(String[] args) throws Exception {
int[] array = {1, 2, 3, 4, 5};
System.out.println(array[0]);
change(array);
System.out.println(array[0]);
}

public static void change(int[] arr) {
arr[0] = -1;
}

/**
* 输出
* 1
* -1
*/

当实际参数为引用类型时,方法会拷贝实参对象的地址值。change方法中拷贝的是array的地址,所以方法内部的arr指向的是和array同样的数组,对arr的修改也会影响array

传递不可变类型参数

如果传递的引用类型是不可变的,那么即使方法内部进行了修改,也不会影响实参。以字符串为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/** 
* 传递不可变参数
*/

public static void main(String[] args) throws Exception {

String string = "1234";
System.out.println(string);
change(string);
System.out.println(string);
}

public static void change(String str) {
str = "4321";
}

/**
* 输出
* 1234
* 1234
*/

参考

  1. JavaGuide:Java 为什么只有值传递?
  2. Java 到底是值传递还是引用传递? - Hollis的回答 - 知乎