Java值传递还是引用传递

关于Java值传递还是引用传递以前概念不是很清楚,也看了很多文章,但是看完也是一知半解的,今天又人在群里发了一道题,经过思考后对于传递问题有了一些明白点了,所以进行记录。

在弄明白传递问题之前我们需要弄清楚以下几个问题:基本数据类型和引用数据类型区别?

基本数据类型分为三类:
1. 数值类型:byte,short,int,long,float,double
2. 布尔类型:boolean
3. 字符类型:character

引用数据类型:String,数组,class,interface

我们拿int和String举例说明不同:

int number=10;
String str="zcc";

区别
我们可以从图中看到,在基本数据类型中变量中存放的是变量的值,在引用数据类型中变量存放的是地址,而这个地址指向变量的值。

好了我们开始正式解析

我们先尝试思考下面代码输出结果是什么?

public class ParamTest3 {
    public void change(int a,int b){
        int temp=a;
        a=b;
        b=temp;
    }
    public static void main(String[] args) {
        int a=10,b=20;
        System.out.println("未经过change处理"+a);
        System.out.println("未经过change处理"+b);
        ParamTest3 paramTest3 = new ParamTest3();
        paramTest3.change(a,b);
        System.out.println("经过change处理"+a);
        System.out.println("经过change处理"+b);
    }
}

结果:

未经过change处理10
未经过change处理20
经过change处理10
经过change处理20

我们发现即使经过了交换的处理我们的a,b值也并没有交换。那么这是为什么呢?
在main方法调用change(int a,int b)时,向a,b传递的是a,b值的副本,因此者两个a,b对应的内容不是一个,change方法中修改的只是自己栈中的内容,并没有修改main中的内容。
在这里插入图片描述

我们再来看看下面程序

public class DemoTest {
    public static void main(String[] args) {
        Person2 person2 = new Person2("阿大");
        chage(person2);
        System.out.println(person2.name);
    }
    public static void chage(Person2 p){
        p = new Person2("阿小");
    }
}
class Person2{
    String name;
    public Person2(String name){
        this.name=name;
    }
}

结果:

阿大

我们看看在堆中代码情况 如图:
在这里插入图片描述
在执行new Person(“阿大”)时在堆中开辟空间,person2持有该内存地址0x123如图一。随后执行chang(person2)方法,将person2作为实际参传递给形参p,注意这个时候传递的是地址的值将地址0x123给了p,如图二。然后执行p = new Person(“阿小”),此时会重新开辟一块0x456的内存赋值给p,如图三。所以输出的是— 阿大

我们先看看上面这种情况是否是引用传递?

首先这一定不是引用传递,如果是引用传递,那么在执行p = new Person(“阿小”)时person2应该指向的是0x456。

所以这应该是实际参数的引用的地址复制了一份给了形式参数,所以这应该是值传递,将引用地址作为值传递给了形式参数

再来分析下面代码

public class DemoTest {
    public static void main(String[] args) {
        Person2 person2 = new Person2("阿大");
        chage(person2);
        System.out.println(person2.name);
    }
    public static void chage(Person2 p){
        p.name="阿小";
        //p = new Person2("阿小");
    }
}
class Person2{
    String name;
    public Person2(String name){
        this.name=name;
    }
}

结果

阿小

在堆中情况如下:
在这里插入图片描述
在这段代码中,并没有对形参进行修改,而是对形参地址中存储内容进行修改。

所以,我们在分析题的时候要明确实参究竟有没有复制一份给形参,如果是基本数据类型,那么就会复制一份给形参。如果传递的是一个地址,那么就要看这个地址有没有改变。

我们再看下面代码:

class ParamTest2{
    public static void main(String[] args) {
        ParamTest2 pt2 = new ParamTest2();
        String name = "zcc";
        pt2.pass(name);
        System.out.println("print in main , name is " + name);
    }
    public void pass(String name) {
        name = "zhangxiaochun";
        System.out.println("print in pass , name is " +name);
    }
}

结果:

print in pass , name is zhangxiaochun
print in main , name is zcc

很多人认为结果应该都是第一句,但是实际却并不是这样的。因为当我们在执行name = “zhangxiaochun”;时,本质上执行的时name = new String(“zhangxiaochun”);所以结果应该是不同的。

所以,Java是值传递。
如果是基本数据类型,传递的是基本数据类型的值的拷贝
如果是引用数据类型,传递的是地址值的拷贝。

最后留一个问题:
在这段代码中除了以这种方式输出阿小还有什么方式?(仅变动一行代码)

public class DemoTest {
    public static void main(String[] args) {
        Person2 person2 = new Person2("阿大");
        chage(person2);
        System.out.println(person2.name);
    }
    public static void chage(Person2 p){
        p.name="阿小"; //输出阿小
        //p = new Person2("阿小");
    }
}
class Person2{
    String name;
    public Person2(String name){
        this.name=name;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值