TransferValue-java传值还是传引用面试陷阱题

打印的结果是什么?

public class TransferValue {

    public void changevalue(String str) {
        str = "xxx";
    }

    public static void main(String[] args) {
        TransferValue test = new TransferValue();
        String str = "abc";

        test.changevalue(str);

        System.out.println(str);
    }
}

运行结果是:abc

我承认第一次做有点掉以轻心了。java中每个方法对应着一个栈帧,一个栈帧有一个专属的局部变量表和操作数栈,栈的结构是后进先出。
执行main方法时,先开一个栈帧,
调用changevalue(String str)时,再开一个栈帧,main方法先进,后出,示意图。
在这里插入图片描述
"abc"是字符串,存放在常量池中。main方法把abc的引用(abc的内存地址值)交给了changevalue()方法.
在这里插入图片描述
两个栈都有一个局部变量叫str,这两个str并不是同一个变量,他们分别存放在不同的局部变量表中,只是他们指向的空间是一样的。(不同方法里的局部变量的名称是可以相同的,因为不在一个作用域里)。
还不理解的话就把changevalue方法的形参改成string,再自己分析分析

public class TransferValue {

    public void changevalue(String string) {
        string = "xxx";
    }

    public static void main(String[] args) {
        TransferValue test = new TransferValue();
        String str = "abc";

        test.changevalue(str);

        System.out.println(str);
    }
}

main方法只是把"abc"的内存地址传过去了,常量池中相同字符串只保存一份,大家都共用常量池里的"abc"。这两个str分别在两个不同的方法中,作用域是不一样的。

表面上看changevalue()把str的内容改掉了,其实是没有!String比较特殊,被final修饰,是不可变类型,字符串一旦创建好了无法修改
在这里插入图片描述
str = “xxx”;本质是重新new了一个字符串"xxx",再把指针重新指向新的字符串"xxx"。原来的字符串”abc"依然在常量池中没用被修改。

idea安装jclasslib,直接上字节码,
看看changevalue()方法做了什么
在这里插入图片描述
在这里插入图片描述

  1. 加载常量池中的"xxx",压入操作数栈中
  2. 存进该栈局部变量中
  3. 退出方法,栈销毁
    自娱自乐,啥也没做!对main方法一点影响都没有。
    在这里插入图片描述
    所以最终打印的结果是:abc

test.changevalue(str);这一步表面上看是main方法把str对象传给changevalue()做修改,实际并不是。由于String字符串特殊不可变,实际上传的是该字符串"abc"在常量池中的内存地址。

再看这题

public class Person {
    private Integer id;
    private String personName;

    public Person() {
    }

    public Person(String personName) {
        this.personName = personName;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }
}

public class TransferValue {

  /*  public void changeValue2(Person person){
        person.setPersonName("xxx");
        System.out.println(person);
    }*/

    //为了避免混淆,这里就写成Person p,跟main方法的person特意做了区分
    public void changeValue3(Person p) {
        p.setPersonName("xxx");
        System.out.println(p);
    }

    public static void main(String[] args) {
        TransferValue transferValue = new TransferValue();
        Person person = new Person("abc");

        System.out.println("personName---" + person.getPersonName());
    }
}


运行结果
personName—xxx

为什么改掉了呢?很简单–因为我们自定义的Person类可以修改。引用类型传递的本质是传递内存地址
在这里插入图片描述
对象是放在堆中的,p和person都同时指向堆内存中Person对象的实际地址,内存中仅有一份。
p.setPersonName(“xxx”);就直接把person对象的名字改掉了,改的是同一个对象,而person对象可以直接被修改。
String被final修饰,创建后不可以被修改,这就是区别。

第三题

public class TransferValue {

    public void changeValue4(int age) {
        age=40;
    }

    public static void main(String[] args) {
        TransferValue transferValue = new TransferValue();
        int age=20;
        transferValue.changeValue4(age);
        System.out.println("age---"+age);
    }
}

运行结果:
age—20

在这里插入图片描述

基本数据类型的传值是值传递,把值拷贝了一份再传递。也就是把20这个值传递过去。

还不懂的话,就看成这样

public class TransferValue {

    public void changeValue4(int a) {
        System.out.println("a的值是"+a);	//20
        a=40;
        System.out.println("a的值是"+a);	//40
    }

    public static void main(String[] args) {
        TransferValue transferValue = new TransferValue();
        int age=20;
        transferValue.changeValue4(20);
        System.out.println("age---"+age);
    }
}


运行结果:
a的值是20
a的值是40
age—20

形参的名字是可以随便修改的。一般情况还是改成一样方便查看。
a=40,跟age=20,没半毛钱关系,作用域都不一样。

结论:基本数据类型传值传的是变量值的拷贝,引用类型传的是对象的内存地址值。String类型比较特殊不可改变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值