java的值传递机制

引用:https://juejin.cn/post/6844903984323362829

简单的说:对于基本数据类型是值传递,对于引用数据类型是地址传递。

1,当进行基本变量交换的时候,系统为main和swap_1分别开辟一个栈区,在main栈区中是最原本变量,在swap_1栈区中使用的是复制main栈区的变量副本,swap_1栈区中,副本原原本本进行完变量交换,而且成功交换,退出swap_1栈区后,main栈区还是main栈区,其中的变量并未改变。
在这里插入图片描述
2,当进行引用变量进行交换的时候,系统会为mian和swap_2分别开辟一个栈区,在main栈区中是原本的引用变量,在swap_2栈区中使用的时候复制main栈区的引用变量副本,注意是引用变量,对于引用变量而言,他的引用是存在于栈中,但其真正的值是存在于堆中,从栈指向堆地址得到自己的值,swap_2栈区中引用变量成功进行交换,但其指向堆中的值跟main指向堆中的值是一样的,也就是说,swap_2修改了堆中的值,当返回main栈区后,在指向堆的时候,获取到的值自然就改变了。
在这里插入图片描述

一:清楚 基本类型 和 引用类型的不同之处

int num = 10;
String str = "hello";

在这里插入图片描述
如图所示,num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。

二:清楚赋值运算符(=)的作用

num = 20;
str = "java";

对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉。
对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。
如上图所示,“hello” 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)
在这里插入图片描述

三:调用方法时发生了什么?参数传递基本上就是赋值操作。

第一个例子:基本类型
void foo(int value) {
    value = 100;
}
foo(num); // num 没有被改变

第二个例子:没有提供改变自身方法的引用类型
void foo(String text) {
    text = "windows";
}
foo(str); // str 也没有被改变
//这里,栈空间创建方法名text,在常量池中没有寻找到"windows",在常量池创建"windows"对象后将地址指向了栈空间中的text。
第三个例子:提供了改变自身方法的引用类型
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4");
}
foo(sb); // sb 被改变了,变成了"iphone4"。

第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"。

重点理解为什么,第三个例子和第四个例子结果不同?

下面是第三个例子的图解:
在这里插入图片描述
builder.append(“4”)之后
在这里插入图片描述
下面是第四个例子的图解
在这里插入图片描述

builder = new StringBuilder(“ipad”); 之后
在这里插入图片描述

String str=“abc”;和String str = new String(“abc”);的区别

String str ="abc"原理

String str ="abc"的原理,采用字面值的方式创建时,JVM会先去字符串常量池中去查找是否存在"abc"这个对象,如果不存在就创建这个字符串,并把地址返回给str。如果存在则直接把"abc"这个字符串的地址返回给str。
在这里插入图片描述

        String x = "abc";
        String y = "abc";
        System.out.println(x==y);//结果为true

在这里插入图片描述

String str = new String(“abc”)原理

String str = new String(“abc”)采用new关键字的方式创建,JVM也会去字符串常量池中查找有没有这个字符串,如果没有的话,就先在字符串常量池里创建"abc"这个字符串,然后再复制一份放在堆里并把地址返回给str。如果字符串常量池里存在该字符串,那么就直接复制一份放在堆里并把地址返回给str。

在这里插入图片描述

        String x = new String("abc");
        String y = new String("abc");
        System.out.println(x == y);//结果为false

在这里插入图片描述

String str="abc"和String str = new String(“abc”)的区别总结为:

创建对象个数不同。

String str=“abc"只在字符串常量池里创建一个对象。(如果字符串常量池里有"abc”,则一个都不创建直接返回地址值给str)
String str = new String(“abc”)在堆内存和字符串常量池各创建一个对象。(如果字符串常量池里有"abc",则只在堆内存创建对象并返回地址值给str)

举例:

public class Test {
	public static void main(String[] args){
		Test s1 = new Test();
		String num = "123";
		String num2 = "123";
		String num3 = new String("123");
		String num4 = new String("123");
		s1.foo(num);
		System.out.println(System.identityHashCode(num));//1829164700
		System.out.println(System.identityHashCode(num2));//1829164700
		// num1 num2 地址都是直接指向的常量池中的“123”对象
		
		System.out.println(System.identityHashCode(num3));//2018699554
		System.out.println(System.identityHashCode(num4));//1311053135
		//num3 num4 地址不一样,因为堆空间存放“123”备份的地址不一样,虽然常量池中的对象和地址是一样的
	}
	  public void foo(String text){
		text = "456";
		System.out.println(System.identityHashCode(text));//366712642
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值