Java的内存模型分为堆和栈。
1、基本数据类型的变量放在栈里。
2、封装类型中,对象放在堆里,对象的引用放在栈里。
值传递
Java在方法传递参数时,是将变量赋值一份,然后传入方法体去执行。
声明一个num变量
①虚拟机分配给num一个内存地址,并且存了一个值0
②当执行方法时,虚拟机复制一个num,比如叫num1,num1和num的地址不同,但是值都是0
③虚拟机将num1传入方法,方法将num1的值改为1
④方法结束,方法外打印num的值,由于num内存中的值并没有改变还是0,所以打印0
封装类型的传递
新建一个product对象,有proName和num两个属性。
①虚拟机在堆中开辟一个product的内存空间,内存中包含proName和num。
②虚拟机在栈中分配给p一个内存地址,这个地址中存的是①中的product的内存地址。
③虚拟机复制了一个p,叫p1,p1和p的内存地址不同,但它们存的值是相同的,都是①中的product的内存地址。
④将p1传入方法,方法改变了①中的proNum和num。
⑤由于p和p1存的都是product的地址,所以执行方法后的p.getNum是改变之后的值。
string类型传递
①虚拟机在堆中开辟一块内存,并存值”abc”。
②虚拟机在栈中分配给str一个内存,内存中存的是1中的地址。
③虚拟机复制一份str,我们叫str’,str和str’内存不同,但存的值都是1的地址。
④将str’传入方法体
⑤方法体在堆中开辟一块内存,并存值”def”
⑥方法体将str’的值改变,存入5的内存地址
⑦方法结束,方法外打印str,由于str存的是1的地址,所有打印结果不变
string和stringbuffer
String str = “ab”;
String str = “abcd”;
而这两行代码却不会报错,可以说是str的值被改变了。
但实际上却是,新建了一个名为"abcd"的字符串放在了常量池中,让str指向了它,而常量池中还有个"ab",这个"ab"是str原本引用的值,它并没有任何的改变。
并不是说str的值被改变了,而是它引用的地址被改变了,String是个对象类型,也有这种原因。
在参数传递中,Stirng 实参地址 传给了 形参 ,形参有了地址,在change方法中,它在做运算的时候(s2 = s1+s2) 却新建了一个字符串"helloworld" 放在常量池中,再加上之前的两个(s1,s2),一共有三个地址。change方法中的s2指向"helloworld",但主方法中的s1、s2依然指向的原来的地址(“hello”、“world”),其中的内容没有任何的改变,所以说是值传递。
而StringBuffer,实参地址传给了形参 ,形参有了地址,在change方法中,它在做运算的时候,没有新建字符串,在常量池中还是只有两个地址,StringBuffer是直接就在s2的地址上的值进行修改。