Java 值传递

Java中只有值传递,没有引用传递

  • 值传递:是指在调用函数时,将实际参数复制一份传递给函数,这样在函数中修改参数时,不会影响到实际参数。其实,就是在说值传递时,只会改变形参,不会改变实参。
  • 引用传递:是指在调用函数时,将实际参数的地址传递给函数,这样在函数中对参数的修改,将影响到实际参数。
1、传递参数是基本类型时
public class TestNum {
    public static void main(String[] args) {
        int num = 3;
        System.out.println("修改前的num值:"+num);
        changeValue(num);
        System.out.println("修改后的num值:"+num);
    }

    private static void changeValue(int num) {
        num = 5;
        System.out.println("形参num值:"+num);
    }
}

在这里插入图片描述

可以发现,传递基本数据类型时,在函数中修改的仅仅是形参,对实参的值的没有影响
需要明白一点,值传递不是简单的把实参传递给形参,而是,实参建立了一个副本,然后把副本传递给了形参。

2、传递参数是引用类型时

首先准备一个Person类

public class Person{

    private int age;
    private String name;

    public Person(){}

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

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

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

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
2.1 引用对象的指向未发生变化
public class TestClass {

    public static void main(String[] args) {

        Person person = new Person(18, "luosanliang");
        System.out.println("对象修改前:" + person);
        changePerson(person);
        System.out.println("对象修改后:" + person);

    }

    public static void changePerson(Person person){
        person.setAge(20);
        person.setName("java");
    }
}

在这里插入图片描述

问题:发现当传递的变量变为引用变量时,方法中形参的修改导致实参也发生了修改
原因:Java当中,对象存放在堆中, 其引用存放在栈中。当实参创建副本传递给形参时,它们实际操作的都是堆内存中的同一个对象


2.2 引用对象的指向发生变化
public class TestClass {

    public static void main(String[] args) {

        Person person = new Person(18, "luosanliang");
        System.out.println("对象修改前:" + person);
        changePerson(person);
        System.out.println("对象修改后:" + person);

    }

    public static void changePerson(Person person){
        // ** 注意:此处重新实例化了一个对象
        person = new Person();
        person.setAge(20);
        person.setName("java");
    }
}

在这里插入图片描述

问题:发现此时代码的结果与** 2.1 **并不相同
原因:形参在方法中重新实例化了一个对象,person = new Person()
此时实参与形参指向的并不是同一个堆内存

### Java值传递与引用传递的区别及实现机制 #### 一、概念区分 在讨论Java中的参数传递时,重要的是要明白Java采用统一的方式——按值调用(call by value)[^1]。这意味着无论何时向方法传递参数,实际上传递给该方法的都是原始数据类型的副本或者是对象引用的一个复制。 对于基本数据类型而言,当作为实参传给形参的时候,会创建一个新的变量来保存这个数值;而对于引用类型,则是将指向堆内存中某个位置的对象地址复制一份交给函数内部使用[^2]。 #### 二、具体表现形式 - **基本数据类型** 当把一个基础数据类型(比如int, float等)当作参数传递给另一个方法时,实际上是在栈桢(stack frame)里创建了一个新的局部变量并赋予其相同的初始值。因此,在被调用的方法内对该参数所做的任何修改都不会影响到原变量的内容。 ```java public static void changeValue(int num){ num = 10; } int a = 5; changeValue(a); System.out.println(a); // 输出仍然是5 ``` - **引用数据类型** 对于像数组或自定义类这样的复杂结构体来说,情况稍微有些不同。虽然也是按照值来进行传递,但是这里所说的“值”,指的是对这些实体所持有的引用而非实体本身。换句话说,就是两个不同的地方持有同一个物体的位置信息。所以如果在一个方法体内改变了由这个引用指向的数据成员,则这种变化也会反映在外面可见的状态上。 不过要注意一点,即使可以改变对象状态,也无法让外部指针重新指向其他实例。因为传递过来的只是原有引用的一份拷贝而已。 ```java class Person { String name; Person(String n) { this.name = n; } @Override public String toString() { return "Person{name='" + name + "'}"; } } public static void modifyObject(Person p) { p.name = "John"; } // 测试代码如下: Person person = new Person("Alice"); modifyObject(person); System.out.println(person.toString()); // 结果为:Person{name='John'} ``` #### 三、深浅拷贝介绍 为了更好地理解和处理涉及可变对象的情况,还需要掌握关于深拷贝(deep copy) 和 浅拷贝(shallow copy)的知识点: - **浅拷贝**是指只复制最外层容器内的元素而不深入到底部层次去逐级构建新对象的过程。简单来讲就是在不破坏原来关系的前提下建立了一套平行映射表单。这样做可能会导致多个看似独立却共享某些部分资源的现象发生。 - **深拷贝**则是完全重建整个树状图谱下的每一个节点直至叶端为止的操作模式。它能够确保源目标之间没有任何关联性存在从而达到真正意义上的隔离效果。 由于Java默认提供的是浅拷贝功能,所以在需要执行深层次克隆操作之前应当先确认当前环境是否支持序列化接口(Serializable),然后再考虑利用第三方库或者手动编码的方式来完成这项任务[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值