本固枝荣 —— Java值传递与引用传递的误区

“按...调用”是一个标准的计算机科学术语,是用来描述各种程序设计语言中关于方法参数的传递方式的。通常有两大类调用方式:按值调用、按引用调用。按值调用(或称值传递)指的是——方法接收的是调用者提供的值按引用调用(或称引用传递)指的是——方法接收的是调用者提供的变量地址

值传递的特点:方法得到的是所有参数值的一个拷贝,且方法不能修改传递给自己的任何参数变量的内容。

众所周知,C/C++是有值传递和引用传递的,而Java语言是否也是如此呢?看了许多的博客和技术文章,有的说Java语言只有值传递,也有的说二者都有(对基本类型是值传递、对对象是引用传递),到底是什么情况呢,决定通过具体代码示例深入了解一下。

情形一:方法参数为基本数据类型情况

public class TestController {
    public static void main(String[] args) {
        int number = -5;
        System.out.println("方法在调用之前number:" + number); //-5
        TestController.abs(number);
        System.out.println("方法在调用之后number:" + number); //-5
    }
    public static int abs(int n) {
        n= 10; //方法尝试修改传入的参数变量
        return Math.abs(n);
    }
}

分析:abs()方法接收number参数前number的值为-5,abs()方法执行完毕后,number的值仍然为-5,也就是说方法并不会去改变参数变量的内容,是一种值传递。参数变量换成其他基本类型结果也是一样。因此,对于基本数据类型的参数都是值传递。

情形二:方法参数为引用数据类型情况

public class TestController {
    public static void main(String[] args) {
        Student stu = new Student("xxwei");
        System.out.println("before---------->" + stu.getName()); //xxwei
        System.out.println("before---------->" + stu); //Student@3b9a45b3
        TestController.update(stu);
        System.out.println("after---------->" + stu.getName()); //xxwei33
        System.out.println("after---------->" + stu); //Student@3b9a45b3
    }
    private static void update(Student student) {
        student.setName("xxwei33");
    }
}

class Student implements Serializable {
    public String name;
    public Student() { }
    public Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

分析:自定义了一个Student对象,main()方法中stu变量是指向Student对象的一个引用变量,通过update()方法执行前后的打印结果可以看出,该update()方法只是改变了对象的状态,并未将引用变量stu指向另一个对象(也就是说并未改变对象的地址,update()方法实际上接收的是一个拷贝的引用),所以对象类型不是引用调用,本质上对象的引用还是一种值传递。

情形三:举个反例,佐证一下情形二

public class TestController {
    public static void main(String[] args) {
        Student stu1 = new Student("Apple");
        Student stu2 = new Student("Huawei");
        System.out.println("stu1-----before------>" + stu1.getName()); //Apple
        System.out.println("stu2-----before------>" + stu2.getName()); //Huawei
        TestController.swap(stu1, stu2);
        System.out.println("stu1-----after------>" + stu1.getName()); //Apple
        System.out.println("stu2-----after------>" + stu2.getName()); //Huawei
    }
    private static void swap(Student m, Student n) {
        Student temp = m;
        m = n;
        n = temp;
    }
}

class Student implements Serializable {...}

分析:定义的swap()功能用于交换两个变量的位置,swap()方法中的m,n变量可以分别看作是stu1,stu2的引用拷贝,m,n变量的确实现了交换,但它们交换对象参数的结果却没有保留下来,打印后的结果中stu1仍然是Apple,也就是说stu1指向的仍然是原来的Student对象,而stu2仍然是Huawei,也就是说stu2指向的也仍然是原来的Student对象,没有实现真正的交换功能。因此,对象类型的参数不是引用调用,对象的引用是通过值进行传递的。

至此,通过这三个情形的例子分析后,可以明确了Java语言只有值传递类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值