java变量存储和参数传递机制
一、Java方法传递机制基本说明
1.形参是基本数据类型
# 传递数据值
2.形参是引用数据类型
# 传递地址值
# 特殊的类型:String、包装类等对象不可变性
举例说明java的不可变性
public class Main {
public static void main(String[] args) {
String str="adfada";
str="yyyy";
System.out.println(str);
}
}
输出:yyyy
虽然输出改变了,但是str在改变前后所指向的对象地址是不一样的,java字符串是保存在常量池中,当str=“adfada"时,常量池开辟一个空间存储"adfada”,当str=“yyyy”,常量池又开辟一个空间来存储"yyyy",所以str这个变量所存储的地址变了,因为str前后不同的地址指向常量池中不同的空间。可以看出,存储“adfada”的空间并没有因为str的改变而去存储改变后的字符串“yyyy”。这就是String的不可变性。
二、代码示例说明
请看下面一段代码,先自己试试输出是什么。
package com.lcl.practice;
import org.junit.Test;
import java.util.Arrays;
public class StringTest {
@Test
public void test(){
int i = 1;
String str = "hello";
Integer num = 200;
int[] arr = {2, 2, 3, 4};
MyData my = new MyData();
change(i, str, num, arr, my);
System.out.println("i = "+i);
System.out.println("str = "+str);
System.out.println("num= "+ num);
System.out.println("arr = "+Arrays.toString(arr));
System.out.println("my.a = "+my.a);
}
public void change(int j, String s, Integer n, int[] a, MyData m){
j += 1;
s += "word";
n += 1;
a[0] += 1;
m.a += 1;
}
}
class MyData{
int a = 10;
}
输出结果:
i = 1
str = hello
num= 200
arr = [3, 2, 3, 4]
my.a = 11
可以看出,i, str, num都没有改变,arr, my.a改变了。接下来我们就来分析一下。
从代码中我们可以看到,首先定义了变量和对象,其中i基本数据类型,str,num,arr, my 都是引用型数据类型。所以i传递的是值,其它传递的是地址值。如图所示是上述代码各个变量的存储形式。
可以看到,上述图左边黄色和蓝色区域是方法区(黄色区域为上述代码主方法区即main方法,蓝色区域是change方法区),栈中存的是基本数据类型和堆中对象的引用。右边常量池和堆,堆一般是存放对象和数组,常量池可以存放String字符串。
从左边黄色和蓝色区域可以看到 各个变量或者对象前后的变化。i是基本数据类型,是值传递,所以j存储的值为2。
str是引用数据类型,所以传递的是地址值,所以s的初始值为0x1234,但是由于change()方法使得又在常量池中开辟了两个新的空间存储“word”和“helloword”(String的不可变性),这是s指向“helloword”,所以s存储的地址值需要变,这里假如变成0x9999。
同理,对于n,地址值也变了,从原先的指向堆中的200变成了另外一个空间201(Integer的不可变性)。对于数组a,虽然传递的是地址,也改变了a【0】的值,但是并没有(也不需要)开辟新的空间。所以a存储的地址值没有变。
对于my对象,和数组类似,只是对对象里的值进行了修改,并未创建新的空间。
当chang方法执行完后,形参变量j s n a m都已经消失了。所以现在只需要看黄色区域的变量的值或者指向的对象值就可以了。可以看到,除了数组a[0]变成了2和,my.a变成了11,其它的都没有变化。