引用: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
}
}
704

被折叠的 条评论
为什么被折叠?



