java传递类_图解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的分布情况,我们可以知道基本数据类型在栈的分布情况。在基本数据类型对象传递给函数时,会在栈内复制一份,即为形参a,b,在swap函数执行之后,在栈内的分布情况,即变为形参a的值变为2,形参b的值变为1,虽然形参发生了变化,但是实参却没有变化。

8efe7320f18e840719e329369118a5aa.png

引用数据类型

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

swap函数执行前

06d8282f220380ebbb3903b6b09e44ca.png

swap函数执行后

2604335ff733d695c266021e4b6bf12f.png

对于swap2函数,o1、o2分别为red、blue的副本,o1、o2分别指向Red Balloon、Blue Balloon对象。在swap2函数执行之后o1、o2分别指向对象的颜色发生变化,即指向的对象发生了变化。

swap2函数执行前

06d8282f220380ebbb3903b6b09e44ca.png

swap2函数执行后

876500bb7a431f88c37498d2dc1e2c62.png

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

6d49f3e00cd91b426448482da90eeff3.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")是等价的。剩下的内容,根据我们前面的分析,就可以知道了。


版权声明:本文为weixin_33882158原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>