likes
comments
collection
share

实际上在Java中,方法中的对象参数也是按值传递的

作者站长头像
站长
· 阅读数 20

方法中对象参数是按引用传递的,这是一种普遍的误解。

举个例子解释一下也让自己更深入理解这个问题

public class demo {
    public static void main(String[] args) {
        String sayHello1 = "你好";
        String sayHello2 = "世界";
        //传递引用类型的参数
        hello(sayHello1,sayHello2);
        //打印交换位置后的字符串②
        System.out.printf("%s%3s",sayHello1,sayHello2);
    }
    public static void hello(String sayHello1,String sayHello2){
        //打印传递的字符串
        System.out.printf("%s%3s\n",sayHello1,sayHello2);
        String temp;
        //修改String变量的值,交换位置
        temp = sayHello1;
        sayHello1 = sayHello2;
        sayHello2 = temp;
        //打印交换位置后的字符串①
        System.out.printf("%s%3s\n",sayHello1,sayHello2);
    }
}

运行结果:

你好 世界

世界 你好

你好 世界

由结果可知,在方法的内部接收到的参数确实为传递过来的字符串引用。所以交换数据后,方法内部的输出语句成功打印了交换后的结果。但是回到main方法打印第二条输出语句的时候却发现并没有交换数据,如果按照引用传递的理解,这个地方应该已经被修改了才对,可是并没有。这究竟是为什么呢?

这个结果就说明:java语言对对象并不是采用引用传递,而是通过值传递的方式来实现引用传递。它实际上传递的是对象引用的副本,这个副本指向了这个对象的引用。所以当你在方法中修改它的值,实际上修改的是这个对象引用的副本,而不是对象引用本身。说的再直白一点,当对这个对象引用的副本进行修改的时候,会为其指向一个新的字符串的地址,但改变的只是副本的引用地址,并不会改变原来的变量指向的地址。

现在,再看一个代码示例

public class demo {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("张三");
        System.out.println(userInfo);
        editUser(userInfo);
        System.out.println(userInfo);
    }

    public static void editUser(UserInfo user){
        user.setName("赵四");
        user.setAge(40);
        user.setSex((byte) 0);
    }
}

class UserInfo{
    private String name;
    private int age;
    private byte sex;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public byte getSex() {
        return sex;
    }

    public void setSex(byte sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

运行结果: UserInfo{name='张三', age=0, sex=0} UserInfo{name='赵四', age=40, sex=0}

为什么这次修改成功了呢?

因为虽然说传递的参数是对象引用的副本,但是副本与对象引用指向的是同一地址。当对相同引用内部的数据进行修改的时候,是没有问题的。而第一个示例中并不是对相同引用内部的数据进行修改,而是相当于直接修改了引用,所以结果才会不同。

再看一个示例就能明白是怎么一回事了,这次稍微修改一下editUser方法中代码

public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("张三");
        System.out.println(userInfo);
        editUser(userInfo);
        System.out.println(userInfo);
}
public static void editUser(UserInfo user){
    user = new UserInfo();
    user.setName("赵四");
    user.setAge(40);
    user.setSex((byte) 0);
}

运行结果: UserInfo{name='张三', age=0, sex=0} UserInfo{name='张三', age=0, sex=0}

当把editUser中的user指向一个新的实例,就会发现方法中的修改不会对传递过来的对象本身造成任何影响。现在就可以得到一个结论:方法不能让一个对象参数引用一个新的对象,但是可以改变对象参数的状态(对象中的变量)。

为什么说对象参数的传递实际上是值传递,因为传递给方法的对象参数实际上只是对象引用的副本,当方法执行结束后,这些副本就会被丢弃,对这些对象本身的修改并没有持久效果,所以说对象引用实际上是按值传递的

转载自:https://juejin.cn/post/7227434605392298040
评论
请登录