成员方法传参机制(非常非常重要!)
1. 基本数据类型的传参机制
- 举例如下:
- 代码分析:
public class MethodExercise01 {
public static void main(String[] args) {
// 创建一个AA 类的对象aa
AA aa = new AA();
int a = 10;
int b = 20;
aa.swap(a, b);// 调用AA 类中的swap 方法,看看会不会影响到main 方法中的a、b。
System.out.println("a=" + a + "b=" + b);// 输出: a = 10, b = 20,结论是不会影响。
}
}
class AA {
// 基本数据类型的传参机制,值传递,两个方法是独立的栈空间,不会相互影响。
public void swap (int a, int b) {
System.out.println("\na和b交换前的值\na=" + a + "\tb=" + b);
// 输出: a = 10 ,b = 20
int tmp;
tmp = a;
a = b;
b = tmp;
System.out.println("\na和b交换后的值\na=" + a + "\tb=" + b);
// 输出: a = 20, b = 10
}
}
- 传参机制解释:
- 基本数据类型的传参机制是值传递/值拷贝,这是大前提;
- 在main 方法中调用了swap 方法后,会在栈内存中新建一个独立的swap 栈空间,程序跳到swap 栈中执行;
- 在swap 栈中隐形地执行了 int a = a(前者是swap 栈中新声明的变量a,后者是main 栈中传递给 swap 栈 的a,两者不同),由于基本类型变量的赋值方式的值传递,因此新声明的a 只是得到了main 方法中a 的值,也就是10,两个方法中的a 是相互独立的,只是变量名相同。同理,变量b 也是如此;
- 因此,在swap 栈中的a、b 这两个变量交换了值,但是当退出swap 栈返回 main 栈后,a、b 的值没有任何改变。
2. 引用数据类型的传参机制
2.1 引用数据类型的传参机制
- 案例引入:
AA 类中编写一个方法 test,可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化?答案:会变化
- 代码分析:
public class MethodExercise01 {
public static void main(String[] args) {
// 创建一个AA 类的对象aa
AA aa = new AA();
int[] arr = new int[3];
arr[0] = 10;
aa.test(arr);
System.out.println("main方法中arr[0]= " + arr[0]);
// arr[0] = 200,被test 方法影响
}
}
class AA {
//引用数据类型的传参机制,引用传递
public void test (int[] arr) {
arr[0] = 200;
System.out.println("test方法中arr[0]= " + arr[0]);
// arr[0] = 200
}
}
- 传参机制解释:
- 引用数据类型的传参机制是引用传递/地址拷贝,这是大前提;
- 在main 方法中调用了test 方法后,会在栈内存中新建一个独立的test 栈空间,程序跳到test 栈中执行;
- 在test 栈中隐形地执行了 int[] arr = arr(前者是test 栈中新声明的数组arr,后者是main 栈中传递给 test 栈 的数组arr,两者不同),由于引用类型变量的赋值方式的引用传递,因此新声明的arr 得到了main 方法中arr 的地址,此时这两个arr 都可以改变存在于堆内存中的数组空间。这两个方法中的a 是相互独立的,只是变量名相同,但是它们对于内存空间的改变是相互影响的。
- 因此,在test 栈中的arr 改变了堆内存空间中arr[0] 的值,当退出test 栈返回 main 栈后,main 栈的 arr[0] 也会发生改变。
- 结论及示意图:
- 结论:引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参。
- 示意图(网课老师的图,有点潦草):
2.2 对象的传参机制
在AA 类中编写一个方法 test200,可以接收一个 Person(age,sal)对象,在方法中修改该对象属性,看看原来的对象是否变化。答案:会变化。
- 当传入的实参是一个对象时,其传参机制类似于引用类型的传参机制,可以类比分析。这里只放示意图。
- 示意图如下:
2.3 思考题
若在test200 方法中执行了下面的语句,会对main 方法中原来的对象有影响吗?
- p = null;
- p = new Person();
- 第一条语句:p = null;
- 相当于在test200 方法中 隐式地执行了 Person p = p,再执行 p = null 这两条语句;
- test200 方法中的新创建了一个Person 类对象 p ,一开始其指向 main 方法中 的p 对象所指向的地址空间,但接着 新建的p = null, 也就是新建的 p 指向了空值;
- 所以最后 test200 方法中新建的p 对main 方法中原来的 p 指向的内存空间是不会有任何影响的。
-
示意图如下:
-
第二条语句:p = new Person();
- 相当于在test200 方法中 隐式地执行了 Person p = p;再执行 p = New Person() 这两条语句;
- 此时在 test200 方法中的新创建了一个Person 类对象 p,其指向一个新开辟的堆内存空间;
- 所以最后 test200 方法中新建的 p 对main 方法中原来的 p 指向的内存空间是不会有任何影响的。
- 示意图如下:
3. 对象克隆
- 克隆对象, 要求得到新对象和原来的对象是两个独立的对象(拥有独立的堆内存空间),只是他们的属性相同。
举例:编写一个方法 copyPerson,可以复制一个 Person 对象,返回复制的对象。
- 代码如下:
public class MethodExercise01 {
public static void main(String[] args) {
// 创建一个AA 类的对象aa
AA aa = new AA();
Person01 p = new Person01();
p.name = "钢铁侠";
p.sal = 3000;
// 创建一个新的Person01类的对象p1 接收克隆出来的对象(内存空间)
Person01 p1 = aa.copyPerson(p);// p 和 p1 是两个独立的对象,只是他们的属性相同。
System.out.println("copy方法中这个超级英雄是:" + p1.name + "他的工资是:" + p1.sal);
}
}
class AA {
// 克隆对象
public Person01 copyPerson (Person01 p) {
//创建一个新的对象/开辟了一个新的堆内存空间
Person01 p1 = new Person01();
p1.name = p.name;//把原来对象的名字赋给 p1.name
p1.sal = p.sal;//把原来对象的工资赋给 p1.sal
return p1;
}
}
class Person01 {
String name;
int sal;
}
- 示意图如下:
- 对象克隆的分析类比上面的对象的传参机制的思考题2,这里就不赘述了。
总结
- 本文是小白博主在学习B站韩顺平老师的Java网课时整理的学习笔记,在这里感谢韩顺平老师的网课,如有有兴趣的小伙伴也可以去看看。
- 最后,如果本文有什么错漏的地方,欢迎大家批评指正!一起加油!!