前言
这是一篇很基础的文章,有一天我突然想到Java中只有值传递,但是为什么在传递对象的时候,里面的值修改后,实参也会被修改,我就特意去了解了一下这些相关的知识。这一学,我发现我之前的一些了解是错误的,不只是是对Java传递参数理解有问题,对C++中这传递也是有问题的。因此我觉得我应该特地写一篇随笔,帮我理解,毕竟感觉真正的弄懂,是能够帮助别人理解。
正文
值传递
简单的基本类型
关于值传递基本类型我就不过多叙述了,感觉有点像水字数一样。
就简单举个例子过一下
public class Main {
public static void change(int a){
a = 2;
}
public static void main(String[] args) {
int a = 1;
change(a);
System.out.println(a);
}
}
运行截图:
基本的数据类型都是这样的情况
传递引用类型
接下来来传递引用类型
现在说一下前言中说我在C++关于传递的错误理解
我一直以为,C++中的引用传递,传递的参数与实参指向同一个对象(这是对的),因此传递过去实际是实参的地址,后面我才发现我理解错了,实际形参就直接理解为就是实参的一个别名。
接下来说说我另一个理解错误的地方(这部分结合值传递引用类型讲解)
我过去的理解,值传递是不可能能够改变实参的,在Java中,我又发现好像可以改变耶,我就以为是不是我记错了,Java中的传递方式也是有两种,除了值传递,还有引用传递,我还以为我记错了,我特意上网查了一下,确实没有,我也特意弄懂了这一部分。
下面我将通过例子进行讲解
class Student {
public int id;
public String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Student{id=" + id + ", name='" + name + "'}";
}
}
public class Main {
public static void change1(Student student) {
student.id = 2;
}
public static void change2(Student student) {
student=new Student(2,"Bob");
}
public static void main(String[] args) {
Student student1 = new Student(1, "Alice");
Student student2 = new Student(1, "Alice");
System.out.println("student1改变前 " + student1);
System.out.println("student2改变前 " + student2);
change1(student1);
change2(student2);
System.out.println("根据change1方法改变后 " + student1);
System.out.println("根据change2方法改变后 " + student2);
}
}
在例子中我们定义了Student类用充当引用对象,方法change1相当于setter方法,改变形参对象内属性值;方法change2则是使更换指向对象。
运行截图:

最后方法change1根据使得实参对象内属性值发生改变,而方法change2却没用使得实参更换指向对象。
原因讲解:
change1(student1)
形参 student1 得到 假设地址为0xAAA 的拷贝。
student.id = 2; 是通过这份拷贝里的地址找到原对象,把 id 改成 2。
原对象确实被改了,因此 student1 打印出 Student{id=2, name='Alice'}。
change2(student2)
形参 student2 得到 假设地址为0xBBB 的拷贝。(因为是new Student()创建,执行两个完全独立的对象)
student = new Student(2,"Bob"); 只是 把这份拷贝里的地址改成了新对象 0xCCC,原来的 student2 仍指向 0xBBB,毫无变化。
所以 student2 打印依旧是 Student{id=1, name='Alice'}。
对应值传递引用对象,更换指向对象,例子很多,里面有很多很隐晦的,如对String赋值,由于String是不可变,用final修饰,看向在实现String更换值了,实际是更换了指向对象;还有Integer的自动装箱,这些例子我参考了一下这篇文章(https://blog.csdn.net/yiridancan/article/details/149813906)
结论
- Java 中进行值传递,方法收到的永远是实参的一份拷贝,也可以说是副本,在传递基本类型时,是传递真正的数,对这份拷贝本身做任何重新赋值都不会影响原来的变量;在传递引用类型时,是传递的是对象地址的副本,而但通过拷贝里保存的对象地址去改对象内部字段是可以的。*