面试常考基础,Java传递方式--值传递

前言

这是一篇很基础的文章,有一天我突然想到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 中进行值传递,方法收到的永远是实参的一份拷贝,也可以说是副本,在传递基本类型时,是传递真正的数,对这份拷贝本身做任何重新赋值都不会影响原来的变量;在传递引用类型时,是传递的是对象地址的副本,而但通过拷贝里保存的对象地址去改对象内部字段是可以的。*