188W+程序员关注过的问题:Java究竟是值传递仍是引用传递?

在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山同样高的问题,好比说这个:Java 究竟是值传递仍是引用传递?访问量足足有 188万+,这不得了啊!说明有不少不少的程序员被这个问题困扰过。实话实说吧,就是其中之一。html

来回顾一下提问者的问题:java

我一直认为 Java 是按引用传递的,可是我看一些博客上说不是的。我就纳闷了,Java 究竟是值传递仍是引用传递?值传递和引用传递有什么区别呢?程序员

若是你也曾被这个问题困扰过,或者正在被困扰,就请随我一块儿来梳理一下问题的答案。打怪进阶喽!bash

0一、值传递和引用传递

什么是值传递,什么是引用传递?咱们须要先把这两个定义搞清楚,才能搞清楚 Java 是按值传递仍是按引用传递。微信

值传递(pass by value)是指在调用方法时将实参复制一份传递到方法中,这样当方法对形参进行修改时不会影响到实参。
引用传递(pass by reference)是指在调用方法时将实参的地址直接传递到方法中,那么在方法中对形参所进行的修改,将影响到实参。this

上面是比较官方的定义,读起来难免生硬。在我看来,值传递和引用传递的关键区别有两点:spa

1)调用方法时有没有对实参进行复制。code

2)方法内对形参的修改会不会影响到实参。cdn

what?值传递和引用传递尚未搞清楚,又来两个新名词:实参和形参。别急,别急。htm

0二、实参和形参

实参和形参理解起来比值传递和引用传递容易的多,前者就好像是一元一次方程,后者就像是一元二次方程。

形参:定义方法名和方法体的时候使用的参数,目的是用来接收调用该方法时传入的参数。
实参:在调用有参方法时传入的参数,方法名后面的括号中的参数一般被称为“实参”。

你们应该都写过“hello world”程序了,就像下面这样。

public class Cmower {
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}
复制代码

其中 args 就至关因而形参,而字符串“hello world”就至关因而实参。若是以为这个例子不容易理解,那再来看一个。

public class Cmower {
    public static void main(String[] args) {
        Cmower cmower = new Cmower();
        cmower.sop("沉默王二");
    }

    public void sop(String name) {
        System.out.println("hello " + name);
    }
}
复制代码

其中“沉默王二”为实参;有参方法 sop(String name) 中的 name 为形参。形参就好像实参与被调用方法之间的一个桥梁,不然调用者无法传递参数,被调用的方法没法接收参数。

0三、基本类型是值传递的

Java 中的数据类型能够分为两种,一种是基本类型,一种是引用类型。我相信你们在看本篇文章以前,就可以达成这样一个共识:基本类型是值传递的。这一点毫无疑问。

public class Cmower {
    public static void main(String[] args) {
        Cmower cmower = new Cmower();
        int age = 18;
        cmower.sop(age);
        System.out.println("main 中的 age " + age);
    }

    public void sop(int age) {
        age = 28;
        System.out.println("sop 中的 age " + age);
    }
}
复制代码

上面这段代码中,sop() 方法的实参 age 为 18,尽管 sop() 方法的形参被修改成 28,但并不会影响实参的值。这一点能够从输出结果中加以证实。

sop 中的 age 28
main 中的 age 18
复制代码

具体的执行过程以下图所示。

0四、引用类型是值传递吗?

你们之因此不肯定 Java 是值传递的仍是引用传递的,缘由就出在这个引用类型上面。单从字面的意思上就容易搞混:引用类型不是引用传递难道仍是值传递?

public class Cmower {
    private String name;

    public String getName() {
        return name;
    }

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

    public static void main(String[] args) {
        Cmower cmower = new Cmower();
        cmower.setName("沉默王二");
        cmower.sop(cmower);
        System.out.println("main 中的 cmower " + cmower.getName());
    }

    public void sop(Cmower cmower) {
        cmower.setName("沉默王三");
        System.out.println("sop 中的 cmower " + cmower.getName());
    }
}
复制代码

main() 方法中,咱们经过 new 关键字建立了一个对象 cmower,并将其 name 属性设置为“沉默王二”;而后将实参 cmower 传递给 sop() 方法,在 sop() 方法中将形参 cmower 的 name 属性修改成“沉默王三”。输出结果是什么样子呢?

sop 中的 cmower 沉默王三
main 中的 cmower 沉默王三
复制代码

呀!实参 cmower 的属性 name 居然不是“沉默王二”而是“沉默王三”了!看看,看看,Java 不是值传递吧?

别急别急。咱们在 main 方法中追加几行代码。

Cmower cmower = new Cmower();
cmower.setName("沉默王二");

Cmower old = cmower;
cmower.sop(cmower);
System.out.println("main 中的 cmower " + cmower.getName());

System.out.println(old == cmower);
复制代码

old == cmower 会是 true 仍是 false 呢?闭上眼睛想想。若是实在是想不出,抛一枚硬币吧,反正不是 true 就是 false。假如引用类型是引用传递的,根据引用传递的定义(形参的修改将会影响到实参),那么结果必定就是 false。

咱们来看一下输出结果:

sop 中的 cmower 沉默王三
main 中的 cmower 沉默王三
true
复制代码

true?开什么玩笑?

很差意思,没有开玩笑。Java 的确是值传递的。只不过,引用类型在调用有参方法的时候,传递的是对象的引用,并非对象自己。而对象的引用在传递的过程当中并无发生改变,虽然对象自己发生了变化。能够经过下面这幅图感觉一下。

这下理解了吧?

0五、总结

来看下面这段代码。

int age = 18;
String name = "沉默王二";
复制代码

age 是基本类型,因此值就直接保存在变量中;而 name 是引用类型,变量中保存的只是对象的内存地址,这种变量通常称之为对象的引用。

基本类型做为参数被传递时确定是值传递;引用类型做为参数被传递时也是值传递,只不过“值”为对应的引用。


好了各位读者朋友们,以上就是本文的所有内容了。能看到这里的都是最优秀的程序员,我必需要为你们点个赞👍。若是以为不过瘾,还想看到更多,我再推荐几篇给你们。

370W+程序员关注过的问题:如何比较 Java 的字符串? 250W+程序员关注过的问题:什么是 NullPointerException? 50W+程序员关注过的问题:为何会发生ArrayIndexOutOfBoundsException?

有收获?就点赞、留言,让更多的人看到这篇文章。

若是想要第一时间看到我更新的文章,能够微信搜索「沉默王二」,关注个人公众号,回复「java」再送你一份精选电子书大礼包,包含这十年来我读过的最优质的 Java 书籍。

相关文章
相关标签/搜索