前面在数组及其内存解析Java和对象的内存解析Java两篇文章中,谈论了有关数组和对象创建时的内存分配问题。其中,前一篇论述对象主要是“数组的动态创建”对应内存区域的变化。后一篇论述对象主要是“类的实例化过程中”属性对应内存区域的变化,于是在这个基础上,接下来我想谈一下对于Java类方法参数的值传递机制的一些理解。
在进入正题之前,先来一些开胃小菜,首先简述一下Java中类的一般结构:
class 类名 { 属性;//Field,也称成员变量,或者域,字段 构造方法;//构造器 方法;//Method,也叫成员方法 代码块;//不常见 内部类;//不常见 }其次,提起形参,就不得不说到局部变量以及局部变量和成员属性的区别。 1、局部变量:可以将其简单定义为:
局部变量是指声明在方法内的方法形式参数(简称“形参”)、代码块内、构造器形式参数、或者构造器内部的变量。一般存放在栈区,也就是在前面文章中提到的虚拟机栈内。
2、成员属性和局部变量的区分 成员属性这个词大家一定不陌生,通俗的说:
成员属性就是指定义在类的“{ }”内的变量。
**两者的相同点在于:** ①定义格式相同:都需要先声明,后使用; ②都有其相应的作用域和生命周期。 **不同点:** ①成员属性一般都有并且可以使用权限修饰符<public;private;protected>进行修饰,来提供一种对外的封装性;而局部变量是不能用权限修饰符进行修饰的; ②成员属性有其对应的默认初始化值;而形参是不存在默认初始化值的,并且在使用前必须对形参进行赋值。 (关于什么是默认初始化值,可以参见文章[数组及其内存解析Java](https://blog.csdn.net/weixin_43524214/article/details/102720707),在此不再进行赘述) ③两者在内存中加载的位置不同:成员属性被加载在堆空间中;形参被加载到栈空间中。好了,在终于要进入正题之前,首先声明一点内容:
编程语言中将参数传递给方法有两种方式值传递(call by value)和引用传递(call by reference),但是在Java语言中只存在值传递。
…废话终于结束了,现在进入正题,请看:
形参即是指方法或成员方法的形式参数, (1)如果形参是**基本数据类型**,则调用方法时实参传递给形参的是实参保存的数据值; (2)如果形参是**引用数据类型**,则调用方法是实参传递给形参的是实参实际所在的地址值。下面通过举例进行详细的解析, (1)如果形式参数为基本数据类型,
public Test { public static void main(String[] args) { //对象实例化,分别在栈区和堆区开辟一块空间 Test test=new Test(); //定义两个变量 int m=10;//在栈区开辟空间 int n=20;//在栈区开辟空间 test.swap(m,n);//调用时,形参作为局部变量被临时创建在栈区中,调用结束后自动销毁 System.out.println("m="+m+",n="+n);//结果:m=10;n=20 } public void swap(int x,int y)//数值交换 { int temp=x; x=y; y=temp; } }对于输出结果,并没有像想象中的“m=20,n=10”,那么:在代码执行过程中,内存中究竟发生了什么事情呢?请看下图。 通过上图可发现:
main()方法中,在调用swap()方法后,作为局部变量的形参x,y自动销毁,并且:这里所说的变量值交换仅仅是对形参值的交换。伴随着形参的销毁,值的交换变得毫无意义,并且可以清除的看到对作为实参的变量m,n没有影响,也就不存在值的交换这回事了。**· (2)如果形式参数为引用数据类型,
public Test { //定义成员属性 int m; int n; public static void main(String[] args) { Test test=new Test();//对象实例化,分别在栈区和堆区开辟一块空间,堆区用于存放成员属性m,n test.m=10;//将堆空间中的m赋值为10 test.n=20;//将堆空间中的n赋值为20 test.swap(test);//调用时,形参作为局部变量被临时创建在栈区中,调用结束后自动销毁 System.out.println("m="+m+",n="+n);//结果:m=20;n=10 } public void swap(Test test)//数值交换 { int temp=test.m; test.m=test.n; test.n=temp; } }对于输出结果,正如想象中的“m=20,n=10”,那么:在这次代码执行过程中,内存中发生了使得之的交换可以实现?请看下图。 通过上图可发现: 在这个过程中,作为形参的test局部变量可以通过实参传递过来的地址值,直接对堆空间中的成员属性进行访问,并调用方法实现属性值的交换。从而实现真正的数值交换的效果。
关于Java方法参数的值传递机制就讲到这里吧,个人感觉能将自己学到的东西写下来,发到网上和大家一起分享还是挺开心的,也有很多收获,比如:以前我是从来不使用画图软件的,哈哈! 当然这篇论述也有不足的地方,比如一些有关String涉及常量池的情况也具有深大迷惑性,但是限于主题,在这里不再进行叙述。 如有不足之处希望大家多多指正,谢谢!
