当前位置:网站首页 > Java基础 > 正文

java基础的传递性



前言

对于Java初学者来说,刚学习Java的时候可能经常会听到调用方法时参数的值传递与引用传递。

但是,实际上Java中方法的参数传递机制只有值传递。 首先,我们要了解一个概念——栈帧。

栈帧位于java虚拟机栈中,用于支持虚拟机进行方法的调用和方法的执行。可以简单的理解为栈帧即方法。

每个方法有自己独立的栈帧。栈帧中有局部变量表、操作数栈、动态链接、返回地址等。

下面我们通过几个例子具体分析java方法的参数传递机制。

方法的参数为基本数据类型

首先我们来看下面代码:

public class ParamTransmit { public static void main(String[] args) { int i = 1; change(i); System.out.println("i = " + i); } public static void change(int j) { j += 1; } }

程序的运行结果为:

在这里插入图片描述

当在main方法中调用change方法时,参数传递相当于将main栈帧中的参数i=1拷贝了一份给change栈帧,此时change栈帧中,变量j的值为1。然后在change方法中执行j java基础的传递性 += 1;运算,j的值变为2,change方法结束。main方法未结束,此时main栈帧中变量i的值仍为1。当传递的参数是基本数据类型时,传递的是数据值,即将参数拷贝一份到被调用方法的栈帧中。该方法中对变量的操作不影响原来栈帧中的变量的值,原栈帧中的变量不被修改。

在这里插入图片描述

方法的参数为引用类型

引用类型变量如String类型,包装类,数组和其他自定义类等。下面依次介绍。

String类型

先上代码

public class ParamTransmit { public static void main(String[] args) { String str = "hello"; change(str); System.out.println("str = " + str); } public static void change(String str) { str += "world"; } }

程序运行结果为:

在这里插入图片描述

首先,在jdk1.7之后,运行时常量池从方法区中移了出来,在堆中开辟了一块区域存放运行时常量。

并且要知道String的值是不可变的,每次对String的操作都会产生新的String对象。

因此,在上面代码中,main方法中调用change方法时,首先是将变量str的值(即运行时常量池中hello的地址)拷贝一份到change栈帧中,此时change栈帧中的变量str也是指向“hello”。

然后执行str += "world";操作,由于String值不可变,此时change栈帧中的str指向新的字符串“helloworld”,str的地址值已改变。

而此时main栈帧中str的值并没有改变,仍指向“hello”,所以main方法中输出的str仍是“hello”。

在这里插入图片描述

包装类

先上代码:

public class ParamTransmit { public static void main(String[] args) { Integer num = 200; change( num); System.out.println("num = " + num); } private static void change(Integer num) { num += 1; } }

程序运行结果为:

在这里插入图片描述

上面代码中,首先Integer num = 200;会自动装箱,先调用Integer.valueOf(200),在堆中创建一个值为200的Integer实例,并将该实例的地址赋值给num。

main方法在调用change方式时传递的是num的地址值,此时change栈帧中的num也指向值为200的Integer实例。

当执行num += 1;时,也自动装箱,先调用Integer.valueOf(201),在堆中创建一个职位201的Integer实例,并将该实例的地址赋值给change栈帧中的变量num,change方法结束。

但此时,main栈帧的num仍指向值为200的Integer实例,因此打印结果为200。

内存结构图如下:

在这里插入图片描述

注:上述内存结构图仅适用于不在-128至127之间的整数。Integer类的自动装箱机制是首先提供一个Integer cache[],用于存放-128至127的缓存。因此,若对实参及对形参操作的结果均在-128至127之间,则实参及形参应指向数组中的元素,而不是堆中新的Integer实例。

数组

直接上代码

import java.util.Arrays; public class ParamTransmit { public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5}; change(arr); System.out.println("arr = " + Arrays.toString(arr)); } private static void change(int[] arr) { arr[0] += 1; }

程序运行结果为:

在这里插入图片描述

数组变量也是引用类型。main方法在调用change方法时,传递的是数组arr的地址值。

change方法内,将数组中第一个元素的值自增1,此时数组中第一个元素的值变为2。

change方法结束,main方法继续执行,此时main栈帧变量arr仍指向该数组,只不过该数组中的元素已被修改。所以输出的是被修改后的数组。

内存结构示意图如下:

在这里插入图片描述

可以引申为多维数组及数组元素为引用类型的情况。

其他自定义类

直接上代码

class MyData { int a = 10; } public class ParamTransmit { public static void main(String[] args) { MyData md = new MyData(); change(md); System.out.println("md.a = " + md.a); } private static void change(MyData md) { md.a += 1; } }

程序运行结果为:

在这里插入图片描述

main方法调用change方法时,同样是将main栈帧中的变量md的值传递到change栈帧中,此时传递的是地址值,指向堆中同一个MyData实例。

然后执行md.a += 1,此时该实例的成员变量a为11。

change方法执行完毕,main方法未结束,main栈帧中的变量md仍指向该实例,此时输出的a为11。内存结构如下图。

在这里插入图片描述

若将上面代码修改如下,会是什么结果呢?

class MyData { int a = 10; } public class ParamTransmit { public static void main(String[] args) { MyData md = new MyData(); change(md); System.out.println("md.a = " + md.a); } private static void change(MyData md) { md = new MyData(); md.a += 1; } }

程序运行结果为:

在这里插入图片描述

main方法调用change方法时,同样传递的是地址值。

然而执行md = new MyData();时,在堆中创建了一个新的实例。

此时change栈帧中的变量md的值变成了新的MyData实例的地址。

然后继续执行md.a += 1;,修改的是新的实例的成员变量。

当change方法调用结束后,main方法继续执行,此时main栈帧中md指向的仍是原来的实例,原实例的成员变量未被修改,仍是10。因此输出结果是10。

内存结构如下图。

在这里插入图片描述

总结

通过以上分析,我们可以知道java的参数传递机制是值传递。

若参数是基本数据类型,传递的是数据值;若参数是引用数据类型,传递的是地址值。

若参数是基本数据类型,对形参的操作不影响实参,因其是不同栈帧的不同变量。

若参数是引用数据类型,并且是String、包装类等。

因其对象的不可变性,对形参的操作会导致其指向新的String或包装类等对象,但不影响实参,实参仍指向原来的对象且该对象并未被修改。

若参数是引用数据类型,并且是数组、StringBuffer及其他自定义类等时,对形参的操作会影响到实参,因其指向的是同一个实例。

版权声明


相关文章:

  • java银行存取款基础2024-10-27 12:18:03
  • java基础教程网站2024-10-27 12:18:03
  • java基础关键词2024-10-27 12:18:03
  • 怎么学好java基础课2024-10-27 12:18:03
  • 女生没有基础学java好吗2024-10-27 12:18:03
  • java基础十字节流2024-10-27 12:18:03
  • java基础常用词2024-10-27 12:18:03
  • java基础程序设计步骤62024-10-27 12:18:03
  • java基础笔记黑马2024-10-27 12:18:03
  • java基础知识的特性2024-10-27 12:18:03