如何判断是值传递还是引用传递

本文介绍了Java中如何判断值传递和引用传递。值传递是实参将值副本传递给形参,操作不影响原始值;引用传递实参传递地址给形参,操作可能影响原始对象。实际上Java所有参数传递都是值传递,不同类型操作结果不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何判断是值传递还是引用传递

值传递

方法被调用的时候,实参将值传递给函数的形参相当于函数拥有了这个实参的副本,函数利用传递来的形参可以进行计算,或者 将传递的值重新赋值,但是因为重新赋值操作的也是传递而来的副本,所以不会影响原始的值

public static void valueCrossTest(int age,float weight){
    System.out.println("传入的age:"+age);
    System.out.println("传入的weight:"+weight);
    age=33;
    weight=89.5f;
    System.out.println("方法内重新赋值后的age:"+age);
    System.out.println("方法内重新赋值后的weight:"+weight);
    }

//测试
public static void main(String[] args) {
       int a=25;
       float w=77.5f; // 是指向值得变量,不是指向地址得引用变量
       valueCrossTest(a,w);
        System.out.println("方法执行后的age:"+a);
       System.out.println("方法执行后的weight:"+w);
}

传入的age:25
传入的weight:77.5
方法内重新赋值后的age:33
方法内重新赋值后的weight:89.5
方法执行后的age:25
方法执行后的weight:77.5

为什么副本传进去之后,最终不影响实参的值
因为:

  • 在程序运行的时候,首先程序运行时,调用mian()方法,此时JVM为main()方法往虚拟机栈中压入一个栈帧,即为当前栈帧,用来存放main()中的局部变量表(包括参数)、操作栈、方法出口等信息,如a和w都是mian()方法中的局部变量,因此可以断定,a和w是躺着mian方法所在的栈帧中
  • 而当执行到valueCrossTest()方法时,java虚拟机也为其往栈中压入一个栈,即为当前栈帧,用来存放valueCrossTest()中的局部变量等信息,因此age和weight是躺着valueCrossTest方法所在的栈帧中,而他们的值是从a和w的值copy了一份副本而得
  • age和weight的重新赋值,只是改变了当前栈帧(valueCrossTest方法所在栈帧)里的内容,当方法执行结束之后,这些局部变量都会被销毁,mian方法所在栈帧重新回到栈顶,成为当前栈帧,再次输出a和w时,依然是初始化时的内容。

引用传递

引用就是真是的值,实参传递给方法调用中的形参的值是地址,在方法体内形参和实参指向的是同一块地址,对形参操作会影响指向的地址的内容

引用传递分两种情况

public class Person {
        private String name;
        private int age;
        public String getName() {
            return name;
        }
       public void setName(String name) {
            this.name = name;
        }
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
}
public static void PersonCrossTest(Person person){
         System.out.println("传入的person的name:"+person.getName());
         person.setName("我是张小龙");
         System.out.println("方法内重新赋值后的name:"+person.getName());
     }
//测试
public static void main(String[] args) {
        Person p=new Person();  
        p.setName("我是马化腾");
        p.setAge(45);
        PersonCrossTest(p);
        System.out.println("方法执行后的name:"+p.getName());
}

传入的person的name:我是马化腾
方法内重新赋值后的name:我是张小龙
方法执行后的name:我是张小龙

在堆中存放了new Person()实例,p为引用类型变量存放在栈帧中的局部变量表中,值为地址存放在栈中经过PersonCrossTest()方法的时候,p的值是地址,此时在方法中操作,操作的是同一个对象。

可以看出person经过了personCrossTest()方法执行之后,内容发送了变化,对形参的操作改变了实际对象的内容,但这不能说明是引用传递,实际上产生这种情况是,实参传递给形参的是地址,只是在一个副本中(一个新的栈帧),在这个副本中形参指向了实参指向的地址,因此对其操作产生了影响,如果此时在方法中重新创建了一个对象,让形参指向它,此时形参指向的地址和实参指向的地址就不一样
比如,在personCrossTest()方法中添加person=new Person();

public static void PersonCrossTest(Person person){
        System.out.println("传入的person的name:"+person.getName());
        person=new Person();
        person.setName("我是张小龙");
        System.out.println("方法内重新赋值后的name:"+person.getName());
    }

public static void main(String[] args) {
        Person p=new Person();  
        p.setName("我是马化腾");
        p.setAge(45);
        PersonCrossTest(p);
        System.out.println("方法执行后的name:"+p.getName());
}

传入的person的name:我是马化腾
方法内重新赋值后的name:我是张小龙
方法执行后的name:我是马化腾

因此实参在自己的副本中指向的是Person对象,进入另一个方法实参将地址传递给形参后,形参在自己的副本中指向的也是Person对象,当在方法中形参指向一个新建的对象的时候,此时形参在自己的副本中指向的就是另一个对象,而实参在自己的副本中指向还是person对象
在这里插入图片描述

  • 图片右侧为xo3333,因此可以知道java中所有的参数传递不管是基本类型还是引用类型,都是值传递,在传递过程中,如果是对基本类型进行操作,原始的值和副本存放的是相同的值,但是不同的栈帧中,不会影响原始的值,如果是对引用类型进行操作,形参和实参都会存放相同的地址值,但是在不同的栈帧中,如果在方法中形参在副本中没有重新赋值指向新对象,则形参和实参在各自栈帧中指向的是堆中同一个对象,如果形参在副本中重新赋值指向新对象,则形参对应的是自己副本中新创建的对象,实参对应的是原始的内容,对形参进行更改不会影响实参的内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值