重申一遍,在Java中只有值传递,没有引用传递

2020-02-05  本文已影响0人  爱吃肉的吠吠

一、基本概念:

值传递和引用传递是指在方法调用中,由调用者传递过来的参数是一个具体的值还是一个地址引用。
我发现小伙伴认为Java中存在引用传递的最大原因就是对上边概念中的这个“地址”有误解,它指的是栈中变量的引用,并不是指堆中对象的地址。

二、在Java中怎么只有值传递的?

在Java中的8大基本数据类型和String中,这个值传递很容易理解,看如下代码:

public static void main(String[] args) {
        int a = 1;
        System.out.println("方法调用前:" + a);
        sum(a);
        System.out.println("方法调用后:" + a);
    }

    private static void sum(int a) {
        a = 2;
    }

输出结果为(这是意料之中的事):

方法调用前:1
方法调用后:1

有很多小伙伴都有如下想法:
Java中的对象有在堆中创建的,而栈中的变量只是一个地址引用,所以当调用方法时传递过去的就是实际就是堆中对象的地址引用。
所以他们认为,在Java中,对象就是引用传递。其实不是的,请仔细阅读引用传递的概念,它是指传递过去的是这个变量的引用而不是对象的引用,也就是传递过去的这个实参就是栈中这个变量的引用。
但是实际是在调用方法时,它传递的就是这个变量的一个一副本,一个复制值,但是这个复制值就是所指向的对象地址还是那个,所以修改这个对象时,其实修改的是堆中对象的值,所以就会改变,看如下示例:

class Student{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student() {
    
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  public static void main(String[] args) {
        Student stu1 = new Student("zhangsan", 12);
        System.out.println("方法调用前:" + stu1.toString());
        change(stu1);
        System.out.println("方法调用后:" + stu1.toString());
    }
 private static void change(Student stu1) {
        stu1.setAge(22);
    }

这个输入结果没有问题:

方法调用前:Student{name='zhangsan', age=12}
方法调用后:Student{name='zhangsan', age=22}

  private static void change(Student stu1) {
        stu1 = new Student();
    stu1.setAge(99);
    }

根据大家的经验,这个输出肯定是:

方法调用前:Student{name='zhangsan', age=12}
方法调用后:Student{name='zhangsan', age=12}

那么重点来了?为什么会是这样,如果它是引用传递,那么我在这里给它new一个新对象,在main方法中的变量应该也是一个新对象啊,因为我改变了它的引用地址,这足以说明这个不是一个引用传递,因为引用传递中,当你改变形参的值的时候,调用方法的实参也应该改变。

上一篇 下一篇

猜你喜欢

热点阅读