java基础–(11)–关于Java中的值传递与“引用传递”

版权声明:编码不易,禁止转载 https://blog.csdn.net/u_ascend/article/details/82876848

结论:Java中都是值传递,没有“引用传递”

(1)基本数据类型传值,对形参的修改不会影响实参;
(2)引用类型传引用的值,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象;
(3)String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。

下面来进行详解:

首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。 它用来描述各种程序设计语言(不只是Java)中方法参数传递方式。

Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。

Example1

    @Test
    public void testInt() {
        int num1 = 10;
        int num2 = 20;

        swapInt(num1, num2);

        System.out.println("num1 = " + num1);
        System.out.println("num2 = " + num2);
    }

    private void swapInt(int a, int b) {
        int temp = a;
        a = b;
        b = temp;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }

结果:
a = 20
b = 10
num1 = 10
num2 = 20

解析:

example 1

在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。另外即使是String, Integer, Double等immutable,也会是上面的情况,请看Example2

Example2

    @Test
    public void testString() {
        String str1 = "hello";
        String str2 = "world";

        swapString(str1, str2);

        System.out.println("str1 = " + str1);
        System.out.println("str2 = " + str2);
    }

    private void swapString(String a, String b) {
        String temp = a;
        a = b;
        b = temp;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }

结果:
a = world
b = hello
str1 = hello
str2 = world

通过上面的例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而对象引用作为参数不一样,请看 Example3

Example3

    @Test
    public void testArr() {
        int[] arr = { 1, 2, 3, 4, 5 };
        System.out.println("改变前arr[0] = " + arr[0]);
        changeArr(arr);
        System.out.println("改变后arr[0] = " + arr[0]);
    }

    private void changeArr(int[] array) {
        // 将数组的第一个元素变为0
        array[0] = 666;
    }

结果:
改变前arr[0] = 1
改变后arr[0] = 666

解析:

example 2

array 被初始化 arr 的拷贝也就是一个对象的引用,也就是说 array 和 arr 指向的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象上。

通过 example3 我们已经看到,实现一个改变对象参数状态的方法并不是一件难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时引用同一个对象。

很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调用和引用调用。有些程序员认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。即使传递的是一个对象的引用也不会改变原有对象的值

Example4

    @Test
    public void testStudent() {
        Student s1 = new Student("小张");
        Student s2 = new Student("小李");

        swapStudent(s1, s2);
        System.out.println("s1.getName() = " + s1.getName());
        System.out.println("s2.getName() = " + s2.getName());
    }

    private void swapStudent(Student x, Student y) {
        Student temp = x;
        x = y;
        y = temp;
        System.out.println("x.getName() = " + x.getName());
        System.out.println("y.getName() = " + y.getName());
    }

结果:
x.getName() = 小李
y.getName() = 小张
s1.getName() = 小张
s2.getName() = 小李

解析:

交换之前:

交换之后:

通过上面两张图可以很清晰的看出: 方法并没有改变存储在变量 s1 和 s2 中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝。但是我们可以改变引用的对象的值,扩展如下

Example5

    @Test
    public void testStudent2() {
        Student s1 = new Student("张三");
        Student s2 = new Student("李四");

        swapStudent2(s1, s2);
        System.out.println("s1.getName() = " + s1.getName());
        System.out.println("s2.getName() = " + s2.getName());
    }

    private void swapStudent2(Student x, Student y) {
        x.setName("张三三");
        y.setName("李四四");
        System.out.println("x.getName() = " + x.getName());
        System.out.println("y.getName() = " + y.getName());
    }

结果:
x.getName() = 张三三
y.getName() = 李四四
s1.getName() = 张三三
s2.getName() = 李四四

上面的Example5我们发现,通过对x,y的改变可以改变原有的对象的值,主要是看我们是对形参的修改还是对形参指向的对象的修改,其中的区别能感觉到么 ,如果没有感觉到。

那就再看一遍Example4,Example5。

再次总结

Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按
值传递的。

下面再总结一下Java中方法参数的使用情况:

  • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
  • 一个方法可以改变一个对象参数的状态。
  • 一个方法不能让对象参数引用一个新的对象。

看这里,看这里

文章总目录:博客导航

 码字不易,尊重原创,转载请注明:https://blog.csdn.net/u_ascend/article/details/82876848

 参考博文:https://github.com/Snailclimb/JavaGuide/issues/12

如果涉及到侵权,请联系我:[email protected],1-2个工作日处理。

作者自己维护的公众平台,感兴趣的来,需要什么可以私聊我,网盘中有大量学习资源,后续慢慢添加。

微信扫一扫

欢迎互喷

猜你喜欢

转载自blog.csdn.net/u_ascend/article/details/82876848