方法调用的基本内存原理:Java中方法调用的基本原理是通过栈来实现的。每当调用一个方法时,就会在栈顶创建一个新的栈帧来保存该方法的参数、局部变量以及方法返回地址等信息。方法调用结束后,该栈帧会被弹出栈。
在Java中,方法调用可以分为静态方法调用和实例方法调用。静态方法调用是通过类名直接调用静态方法,而实例方法调用则必须通过对象引用来调用。
当方法被调用时,Java虚拟机会首先在方法区中查找该方法的字节码,然后将其加载到内存中,并对其进行解析和验证。接着,Java虚拟机会为该方法创建一个新的栈帧,并将该栈帧推入栈顶。在方法执行期间,Java虚拟机会使用该栈帧来保存方法的各种信息。
当方法调用结束时,Java虚拟机会从栈顶弹出该方法的栈帧,并将栈帧所占用的内存释放掉。此时,程序将回到方法调用的原始位置,并继续执行后面的代码。
如图为例:main方法调用,先进栈,main方法中调用eat方法,eat方法进栈,eat方法中调用study方法,study方法进栈,study方法执行完后出栈。栈是先进后出原理。
内存角度引申概念:
基本数据类型:数据值是存储在自己的空间中。
特点:赋值给其他变量,也是赋的真实的值。
范例:
int a=10;
int b = a;
赋值给b的是真实值10
引用数据类型:数据值是存储在其他空间中,自己空间中存储的是地址值。
特点:赋值给其他变量,赋的是地址值。
范例:
int[] arr1 = {1,2,3};
int[] arr2 = arr1;
赋值给arr2的是arr1的地址值,指向堆空间的同一块内存
在java中方法传递参数不管是基本数据类型还是引用数据类型都是值传递
基本数据类型传参说明:在JAVA中,方法传递基本数据类型的原理主要是值传递,也就是将实参的值复制一份传递给形参,方法内部对形参的改变不会影响到实参的值。
具体来说,当我们调用一个方法时,会将实参的值复制一份传递给形参。这个值的副本在方法内部与原始值没有任何关系,因此,如果在方法内部改变形参的值,不会影响到实参的值。这是因为,在JAVA中,基本数据类型的变量是存储在栈内存中的,当方法执行完毕后,该栈帧会被立即销毁,形参也就随之消失了,不会对实参造成任何影响。
例如,我们定义一个方法add,添加两个整数,并将其返回:
public int add(int a, int b){
int sum = a + b;
return sum;
}
调用该方法:
int x = 5;
int y = 10;
int z = add(x, y);
System.out.print(z);
在方法调用过程中,实参x和y的值被复制到了形参a和b中。方法内部计算sum的值,并将其返回。返回值被赋给了变量z,z的值是15。在这个过程中,实参x和y的值并没有发生任何改变。
需要注意的是,在JAVA中,虽然方法传递基本数据类型是值传递,但是对于引用类型,传递的是对象的引用,也就是地址的值。因此,在方法内部改变对象的属性会影响到实参所引用的对象。
引用数据类型传参说明:在Java中,方法传递引用数据类型是指方法的参数是引用类型的变量,当这个变量作为参数传递给方法时,实际传递的是引用的地址,而不是对象本身。因此,在方法中修改引用数据类型的值时,会影响原始的对象。(但原理也是值传递,为值传递中的共享对象传递,并不是引用传递)
下面通过实例说明这个过程。
public class ReferenceType {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
System.out.println("Before calling method, arr[0] = " + arr[0]);
changeArr(arr);
System.out.println("After calling method, arr[0] = " + arr[0]);
}
public static void changeArr(int[] arr) {
arr[0] = 100;
}
}
以上代码中,定义了一个整型数组arr
,数组的第一个元素为1。然后,调用changeArr
方法,将arr
作为参数传递给方法。在方法中,将arr
的第一个元素改为100。最后输出arr
的第一个元素的值。运行以上代码,输出如下:
Before calling method, arr[0] = 1
After calling method, arr[0] = 100
可以看到,当我们在changeArr
方法中修改参数arr
的值时,原始的数组arr
的第一个元素的值也被改变了。
总之,在Java中,当传递引用类型的变量作为方法参数时,实际传递的是引用的地址,方法内部对引用类型变量的操作会改变原始对象。