1.Java中只有值传递
相较于其他程序设计语言(比如 C++、 Pascal)提供的两种参数传递的方式,在 Java 中只有值传递。
- 值传递:方法接收的是实参值的拷贝,会创建副本。
- 引用传递:方法接收的直接是实参的地址,而不是实参内的值,这就是指针,此时形参就是实参,对形参的任何修改都会反应到实参,包括重新赋值。
2.一段Java程序是如何运行的
在讨论Java的值传递之前,先来看看一段Java程序运行时,JVM的内存变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class MethodExampleTest { public static void main(String[] args) { method1(10); } private static void method1(int x) { int y = x + 1; Object m = method2(); System.out.println(m); } private static Object method2() { Object n = new Object(); return n; } }
|
首先当我们运行这个类的时候,首先做的事就是类加载,将该类的字节码文件加载到JVM虚拟机中,对应其中的方法区内存(为了观感,这里使用源代码的形式)
加载完成之后首先启动对应main的主线程,同时分配一块栈内存,之后由任务调度器调度执行,当CPU核心的时间片分给了我们的主线程,main方法作为入口首先被分配一块栈帧,配合每个线程独有的程序计数器(记录当前线程正在执行的字节码指令地址),开始运行主线程中的代码(栈帧中的局部变量表对应方法中的局部变量和方法参数)

方法运行并发现main方法需要调用method1,同上创建出一块栈帧,根据程序计数器执行代码并进行赋值,直到执行到调用method2

再次创建出method2栈帧,发现需要创建对象于是在堆中创建一个Object对象并赋值,直到执行到return语句

直到方法依次调用结束,释放无用栈帧,并根据记录的返回地址,继续执行接下来的代码直到所有栈帧均被释放,程序运行结束。
经过上面的内容在来看Java的值传递,相信下面的几个例子已经难不倒你了。
3.值传递的几个例子
1.传递基本类型参数
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) { int num1 = 10; int num2 = 20; swap(num1, num2); System.out.println("num1 = " + num1); System.out.println("num2 = " + num2); }
public static void swap(int a, int b) { int temp = a; a = b; b = temp; System.out.println("a = " + a); System.out.println("b = " + b); }
|
在 swap() 方法中,a、b 的值进行交换,并不会影响到 num1、num2。因为交换操作发生在自己的方法栈帧中。作为副本的内容无论怎么修改,都不会影响到原件本身。
2.传递引用参数类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public static void main(String[] args) { int[] arr = { 1, 2, 3, 4, 5 }; System.out.println(arr[0]); change(arr); System.out.println(arr[0]); }
public static void change(int[] array) { array[0] = 0; }
|
这里看着像引用传递,但其实传递的还是值,这个值就是数组在堆内存中的地址,由 arr 与 array 共同指向,所以方法内部的修改才能影响到实参
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 class Person { private String name; }
public static void main(String[] args) { Person xiaoZhang = new Person("小张"); Person xiaoLi = new Person("小李"); swap(xiaoZhang, xiaoLi); System.out.println("xiaoZhang:" + xiaoZhang.getName()); System.out.println("xiaoLi:" + xiaoLi.getName()); }
public static void swap(Person person1, Person person2) { Person temp = person1; person1 = person2; person2 = temp; System.out.println("person1:" + person1.getName()); System.out.println("person2:" + person2.getName()); }
|
这里与上面的那种情况又有所不同,在进行方法调用的时候,由于是值传递,person1与person2作为xiaoZhang与xiaoLi的拷贝,各自存在不同的栈帧,正因为如此,方法栈帧内部的交换不会影响到其他栈帧,所以才没有影响到原来的 xiaoZhang 与 xiaoLi