图解Java传递类型

Java的传递类型究竟是值传递还是引用传递,相信大多数小伙伴们都很迷惑,也许有小伙伴知道是值传递,但是不不知道怎么说明。同时这也是一个很经典的面试题,打开文章的你也遇到过吧。

话不多说,先说结论:

Java严格按照值传递。


值传递与引用传递

值传递: 在函数调用的过程中,将实参复制一份给形参,在函数中执行的对象是形参。

引用传递: 在函数调用的过程中,将实参的地址传递到函数中,在函数中执行的对象是真实的实参。

首先,我们先弄明白什么值传递和引用传递的具体含义。

值传递,是将我们传递给函数的对象进行复制,而真正传递进函数的是复制的对象,而不是我们传递给函数的对象,所以我们在函数内对于对象的修改,不会影响我们传递给函数的对象(实参),只会影响形参。

引用传递,是将我们传递给函数的对象的地址传递到函数里面,如果我们在函数中,对对象进行了修改,是会影响我们传递给函数的对象(实参)的。

值传递 引用传递
根本区别 会创建副本 不会创建副本
表现 函数无法改变原始对象 函数可以改变原始对象

代码演示

我们可以根据传递给函数的对象的不同,分别演示基本数据类型和引用数据类型的对象

基本数据类型

基本数据类型演示代码

public class ShowCode {
    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        swap(a, b);
        System.out.println("print in main, a = " + a + ", b = " + b);
    }

    private static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
        System.out.println("print in swap, a = " + a + ", b = " + b);
    }
}
复制代码

代码的执行结果:

print in swap, a = 2, b = 1
print in main, a = 1, b = 2
复制代码

对于这段代码的演示结果,相信屏幕前的你很清楚。当传递参数是基本数据类型的时候,实际传递的参数的副本,所以在swap函数中,对于对象的修改不会影响实际的对象。

引用数据类型

引用类型演示代码

public class Balloon {
    private String name;
    private String color;

    public Balloon(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}
复制代码
public class PassMain {
    public static void main(String[] args) {
        Balloon red = new Balloon("Red Balloon", "Red");
        Balloon blue = new Balloon("Blue Balloon", "Blue");
        Balloon yellow = new Balloon("Yellow Balloon", "Yellow");

        System.out.println("=============  1  ===============");
        swap(red, blue);
        System.out.println("Red Balloon color is " + red.getColor());
        System.out.println("Blue Balloon color is " + blue.getColor());

        System.out.println("=============  2  ===============");
        swap2(red, blue);
        System.out.println("Red Balloon color is " + red.getColor());
        System.out.println("Blue Balloon color is " + blue.getColor());

        System.out.println("=============  3  ===============");
        paint(yellow);
        System.out.println("Yellow Balloon color is " + yellow.getColor());
    }

    public static void swap(Object o1, Object o2) {
        Object temp = o1;
        o1 = o2;
        o2 = temp;
    }

    public static void swap2(Balloon o1, Balloon o2) {
        String temp = o1.getColor();
        o1.setColor(o2.getColor());
        o2.setColor(temp);
    }

    private static void paint(Balloon balloon) {
        balloon.setColor("Black");
        balloon = new Balloon("Green Balloon","Green");
        balloon.setColor("White");
    }
}
复制代码

代码执行结果

=============  1  ===============
Red Balloon color is Red
Blue Balloon color is Blue
=============  2  ===============
Red Balloon color is Blue
Blue Balloon color is Red
=============  3  ===============
Yellow Balloon color is Black
复制代码

对于这段代码的结果,屏幕面前的你,有没有感觉有点转不过来。哈哈,听我细细道来。

swap函数中,交换了两个引用数据类型的对象,实际对象没有变化。

swap2函数中,交换了两个引用数据类型的对象的颜色,实际对象却发生了变化。

paint函数中,对引用数据类型的对象的颜色,实际对象发生了变化。

底层原理

对于值传递,无论是值类型还是引用类型,都会在调用栈上创建一个副本,不同是,对于值类型而言,这个副本就是整个原始值的复制。而对于引用类型而言,由于引用类型的实例在堆中,在栈上只有它的一个引用(一般情况下是指针),其副本也只是这个引用的复制,而不是整个原始对象的复制。

基本数据类型

在基本数据类型的代码演示中,根据对象在JVM的分布情况,我们可以知道基本数据类型在栈的分布情况。在基本数据类型对象传递给函数时,会在栈内复制一份,即为形参ab,在swap函数执行之后,在栈内的分布情况,即变为形参a的值变为2,形参b的值变为1,虽然形参发生了变化,但是实参却没有变化。

Java基本数据类型传递.png

引用数据类型

在引用数据类型的代码演示中,对于swap函数,o1o2分别为redblue的副本,o1o2分别指向Red BalloonBlue Balloon对象。在swap函数执行之后o1o2分别指向Blue BalloonRed Balloon对象,即指向的对象发生了变化。


swap函数执行前

swap函数执行前.png

swap函数执行后

swap函数执行后.png


对于swap2函数,o1o2分别为redblue的副本,o1o2分别指向Red BalloonBlue Balloon对象。在swap2函数执行之后o1o2分别指向对象的颜色发生变化,即指向的对象发生了变化。


swap2函数执行前

swap2函数执行前.png

swap2函数执行后

swap2函数执行后.png


对于paint函数,ballon分别为yellow的副本,ballonyellow都指向Yellow Balloon对象。在paint函数执行之后yellow先改变了Yellow Balloon对象的颜色,之后指向了Green Balloon对象,最后又改变Green Balloon对象的颜色为白色。

paint函数执行前后.png


最后我们可以知道,无论是基本数据类型还是引用数据类型的对象,Java都是值传递。

思考题

public class StringTest {
    public static void main(String[] args) {
        String name = "Hello Java";
        passStr(name);
        System.out.println("name ==" + name);
    }

    private static void passStr(String str) {
        str = "Hello World";
    }
}
复制代码

读到这里,预测一下最后打印的是Hello Java还是Hello World?

最后结果是Hello Java,你猜对了没有?其实想知道结果,只需要知str = "Hello World"str = new String("Hello World")是等价的。剩下的内容,根据我们前面的分析,就可以知道了。

猜你喜欢

转载自juejin.im/post/5e608f8651882549112b463f
今日推荐