Java共分为两种数据类型:基本类型,对象类型
基本类型:
6种数据类型:byte,short,int,long,float,double
1种布尔类型:boolean
1种字符类型:char
对象类型:
类类型,接口类型,数组
基本类型的变量保存了“原始值”,即变量保存值本身。
引用类型变量保存了“引用地址”,"引用地址"指向内存空间的地址,代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用地址所表示的地址的位置。
基本数据类型在声明时,系统就给它分配空间:
int a;
a = 1;//在声明a时,系统就给a分配了空间
引用类型在声明时,系统只分配了引用空间,而没有分配数据空间:
StringBuffer sb;//这一步只分配给sb变量引用空间,而没有数据空间
sb = new StringBuffer();//这一步开辟数据空间存放StringBuffer对象,并把数据空间首地址传给sb变量
//如果没有上一步,这里会报 The local variable sb may not have been initialized 的错误,即对象的数据空间没有分配
sb.append(1);
注意:“引用”也是占用空间的,一个空对象的引用大小大约是4byte
所以方法调用时,传入基本数据类型即传入了数据本身,传入引用类型实际上传入的是引用地址。
值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。
注意:
String,Integer,Double等几个装箱类型比较特殊,它们都是immutable类型,因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待,可以认为是和基本数据类型相似。
例如:
public static void test(){
String s1 = "hello";
String s2 = "world";
System.out.println(s1 + "---" + s2);
change(s1, s2);
System.out.println(s1 + "---" + s2);
StringBuffer sb1 = new StringBuffer("hello");
StringBuffer sb2 = new StringBuffer("world");
System.out.println(sb1 + "---" + sb2);
change(sb1, sb2);
System.out.println(sb1 + "---" + sb2);
}
public static void change(StringBuffer sb1, StringBuffer sb2){
sb1 = sb2;
sb2.append(sb1);
}
public static void change(String s1, String s2){
s1 = s2;
s2 = s1 + s2;
}
输出结果: