Java中的参数传递到底是值传递还是参数传递

先下结论:在 Java 语言中,本质只有值传递,而无引用传递

1.值类型&引用类型

  1. 值类型就是Java 中的 8 大基础数据类型

    • 整数型:byte、short、int、long
    • 浮点型:float、double
    • 字符类型:char
    • 布尔类型:boolean

    所谓的值类型指的是在赋值时,直接在栈中(Java 虚拟机栈)生成值的类型

  2. 引用类型是指除值类型之外的数据类型

    • 类、接口
    • 数组
    • 字符串
    • 包装类(Integer、Double…)

    所谓的引用类型是指,在初始化时将引用生成栈上,而值生成在堆上的这些数据类型

基本类型和引用类型内存中的不同
int age = 10;
String str = "hello";

在这里插入图片描述

如上图所示,age是基本类型,值就存在栈中的变量里

而str是引用类型,栈中的变量保存的只是堆中实际对象的地址,一般称这种变量为引用,引用指向实际对象,实际对象中保存内容

赋值时内存的变化
int age = 24;
String str = "world";

在这里插入图片描述

对于基本类型age,赋值运算符会直接改变变量的值,原来的值被覆盖掉

对于引用类型str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象(“hello” 字符串对象)不会被改变(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)

2.关于值传递

值传递(Pass By Value)指的是方法传参时,传递的是原内容的副本,因此对副本进行如何修改都不会影响原内容
public class PassByValue {
	private static int x=22;
	public static void updateValue(int value){
		value = 3 * value;
	}
	public static void main(String[] args) {
		System.out.println("调用前x的值:"+x);
		updateValue(x);
		System.out.println("调用后x的值:"+x);
	}
}

运行结果

调用前x的值:10
调用后x的值:10

执行流程

在这里插入图片描述

分析结论

当传递方法参数类型为基本数据类型(数字以及布尔值)时,一个方法是不可能修改一个基本数据类型的参数

3.关于引用传递

引用传递(Pass By Reference)指的是方法传参时,传递的是参数本身,因此对参数进行任意修改都会影响原内容
public class User {
    private String name;
    private int age;
    public User(String name, int age) {
      this.name=name;
      this.age=age;
    }
    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 class PassByReference {
	private static User user=null;
	public static void updateUser(User student){
		student.setName("change");
		student.setAge(28);
	}
	public static void main(String[] args) {
		user = new User("start",18);
		System.out.println("调用前user的值:"+user.toString());
		updateUser(user);
		System.out.println("调用后user的值:"+user.toString());
	}
}

运行结果

调用前user的值:User [name=start, age=18]
调用后user的值:User [name=change, age=28]

很明显,user对象的值被改变了,也就是方法参数类型为引用类型的时候,引用类型对应的值将会被改变

执行流程

在这里插入图片描述

分析结论

当传递方法参数类型为引用数据类型时,一个方法将修改一个引用数据类型的参数所指向对象的值

分析到这里,我们会发现,明明从代码中看到,既有值传递又有引用传递啊,可惜上面的代码其实是有一定的误导性的,下面再举一个例子来说明Java中只有值传递而没有引用传递

public class PassByValue {
	private static User user=null;
	private static User stu=null;
	/**
	 * 交换两个对象
	 * @param x
	 * @param y
	 */
	public static void swap(User x,User y){
		User temp =x;
		x=y;
		y=temp;
	}
	public static void main(String[] args) {
		user = new User("user",26);
		stu = new User("stu",18);
		System.out.println("调用前user的值:"+user.toString());
		System.out.println("调用前stu的值:"+stu.toString());
		swap(user,stu);
		System.out.println("调用后user的值:"+user.toString());
		System.out.println("调用后stu的值:"+stu.toString());
	}
}

运行结果

调用前user的值:User [name=user, age=26]
调用前stu的值:User [name=stu, age=18]
调用后user的值:User [name=user, age=26]
调用后stu的值:User [name=stu, age=18]

看到这里,是不是又会有疑惑了?如果是按照引用传递来说的话,user和stu的值会被交换啊,但实际运行结果是没有交换

通过下面的流程图可以看出,交换的只是user和stu的拷贝值,swap方法结束后,x、y都被释放,原来的user和stu仍然引用之前的对象

x和y只是user和stu这两个引用的副本,并不是将user和stu这两个引用指向的对象传给了swap方法,并且对象的引用是在栈上存在的,引用副本的传递也就是值传递,而不是引用对象的传递,前面的之所以能够修改引用数据,是因为原始引用和引用副本均指向同一个对象,而对对象进行操作的时候,就是切切实实的改变了这个对象,即使方法结束,传入方法的引用的拷贝值被销毁,此时对象已经被改变,所以看起来像是符合引用传递的定义,但是并不是引用传递
在这里插入图片描述

4.总结

在 Java 语言中只有值传递,主要是看这个值是什么,如果是简单值变量就拷贝了一份具体值,如果是引用变量就是拷贝了一份内存地址,方法传参时只会传递副本信息而非原内容。我们还知道了基础数据类型会直接生成到栈上,而对象或数组则会在栈和堆上都生成信息,并将栈上生成的引用,直接指向堆中生成的数据

参考:java基本数据类型传递与引用传递区别详解_zejian_的博客-CSDN博客_java的值传递和引用传递区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值