为什么说java中只有值传递?

栏目: Java · 发布时间: 6年前

内容简介:这几天在整理java基础知识方面的内容,对于值传递还不是特别理解,于是查阅了一些资料和网上相关博客,自己进行了归纳总结,最后将其整理成了一篇博客。值传递是指在调用函数时将实际参数引用传递是指在调用函数时将实际参数的地址

这几天在整理 java 基础知识方面的内容,对于值传递还不是特别理解,于是查阅了一些资料和网上相关博客,自己进行了归纳总结,最后将其整理成了一篇博客。

值传递

值传递是指在调用函数时将实际参数 复制 一份传递给形参,这样在函数中对形参的修改将不会影响到实际参数的值。

引用传递

引用传递是指在调用函数时将实际参数的地址 直接传递 到形参,那么在函数中对参数所进行的修改,将会影响到实际参数的值。

我们可以使用一段程序来验证 Java 中只有值传递

/**
 * 验证java中只有值传递
 * Dmego 2018-8-27
 */

class User{
    
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

public class TestValue {
    public static void change(User user2,int a2){
        System.out.println("改变之前:"+user2.getName()+",a2="+a2);
        
        user2.setName("李四"); //改变 user2 的 name 值
        a2 = 10; //改变 a2 的值
        System.out.println("改变之后:"+user2.getName()+",a2="+a2);
        
        user2 = new User(); //将 user2 重新指向一个新对象
        user2.setName("王五");
        System.out.println("重新指向一个新对象后:"+user2.getName());
    }

    public static void main(String[] args){
        User user1 = new User();
        user1.setName("张三"); //初始化 user1 的 name 为张三
        int a1 = 5; //初始化 a1 的值为 5
        change(user1,a1); //调用方法验证传值方式
        System.out.println("调用方法后:"+user1.getName()+",a1="+a1);
    }
}

运行这段程序,输出结果为:

改变之前:张三,a2=5
改变之后:李四,a2=10
重新指向一个新对象后:王五
调用方法后:李四,a1=5

结果分析

为什么说java中只有值传递?

下面我们以上图为辅助,来分析这段程序,首先我们定义了一个 User 类,然后在测试类中实例化了一个 User 对象,名为 user1 ,并且为其赋值 name = '张三' ,此时在内存中如 图1 所示,实例化一个对象相当于在堆中开辟了一块内存,内存地址为 017 ,此时这个对象的引用为 user1 ,内存地址为 001 ,它保存了该对象在内存中的地址,也就是指向了该对象。接下了,我们调用方法 changeVaulue() ,来尝试改变 user1name 值以此验证 java 中的传值方式。

我们将 user1 作为实参传给 changeValue() 方法,形参 user2 来接受这个实参,在这里就体现出了两种传参方式的不同。如果是按值传递,那么就像定义的那样,如 图2 所示, user2user1 的一份副本,也就是说在传递参数时,将 user1 (本身是一个对象的引用),复制了一份,名为 user2 ,它同样也是一个对象的引用,并且 user1user2 此时指向同一个对象。而如果是引用传递,也如同定义的那样,如 图5 所示,在传递参数时,是直接将 user1 传递给了形参,只是换了一个名字叫做 user2 ,但是本质上 user1user2 其实是同一个。它是一个对象的引用。

接着来分析输出的结果,不管是按值传递还是引用传递,第1行输出的结果一定都是 张三 ,因为都是指向同一个对象。对于第2行输出,我们还是无法判断是哪种方式,因为都是改变同一个对象,值也会改变;关键在于第3行输出和第4行输出,此时,我们将 user2 重新指向了一个新的对象,并且为这个对象赋值 name = '王五' ,如果是 引用传递 的方式,那么 user1 同样也会改变指向,指向新的这个对象,最后一行调用方法之后输出的结果将会和第3行一样是 王五 ,但是事实输出的是 李四 ,这表明 user1user2 其实并不是同一个。真实的调用过程如 图2 ~ 图4 所示,这样才会使得 user2 指向一个新的对象后, user1 指向的对象并没有改变,还是原来那个对象。

对于基本类型的参数来说, a1 的值最后没有改变,说明在执行方法时, a2a1 的一个副本。对于引用类型的参数来说,例如 User 对象,在调用方法时,实际上是将其引用 user1 作为实际参数,那么传递给形参的将是该引用的一份副本引用 user2 ,虽然说这是两份引用(好比 a1a2 的关系)。但是却指向同一个对象,所有的操作也都是对这同一个对象而言的。

最后举一个例子来形象的说明这一切,假如你有一把你房间的钥匙,并且在上面刻上了你的名字,这个过程好比给一个 int 类型的 a1 初始化值为 5 。你的朋友和你关系非常好,想要你房间的钥匙,此时你并没有直接把你的钥匙给他,而是复制了一把新的钥匙,这个钥匙也能开你的房间的门。而你的朋友在这把新钥匙上刻上了他的名字。这个过程就好比调用 change() 方法,把 a1 复制了一份赋值给 a2 ,此时修改 a2a1 没有任何关系,你朋友在新钥匙上刻他名字也不会影响你手上那把原始的钥匙。关键是这两把钥匙都能开你的房间,就好比 user1user2 都指向同一个对象。此时你朋友用这把新钥匙打开了你的房间,将你房间电视机砸了。这个过程好比改名 李四 。这时你拿着你的钥匙打开你房间必然会看到这样的场景——电视机被砸了。就如同调用方法后 user1 变成了 李四 。在调用方法的过程中,最后 user2 重新指向了一个新的对象,这就好比你的朋友将你复制给他的钥匙再次进行了加工,此时不能开你房间的门,但是能开他自己的房间,他用这把钥匙开自己的房间然后把自己的电视砸了这并不会影响到你房间的电视,也就是说最后 user1 的名字并不会变成 王五 。这就是 java 中的值传递。当然了,如果是引用传递,那么这个例子中从头到尾将会只有一把钥匙,最后的结果也将会不同。

尾声

通过以上分析我们可以知道。 Java 中只有 值传递 这一种方式,只不过对于引用类型来说, 传递的参数是对象的引用 罢了。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms for Image Processing and Computer Vision

Algorithms for Image Processing and Computer Vision

Parker, J. R. / 2010-12 / 687.00元

A cookbook of algorithms for common image processing applications Thanks to advances in computer hardware and software, algorithms have been developed that support sophisticated image processing with......一起来看看 《Algorithms for Image Processing and Computer Vision》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码