引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值,那么调用这个方法是传入的变量的值也将改变.
值类型表示复制一个当前变量传给方法,当你在这个方法中改变这个变量的值时,最初生命的变量的值不会变.
【值类型】(也被称为基本类型)
基本数据类型常被称为四类八种
四类:
1:整型 2:浮点型 3:字符型 4:逻辑型
八种:
1:整型3种 byte,short,int,long
2:浮点型2种 float,double
3:字符型1种 char
4:逻辑型1种 boolean
【引用类型】
除了四类八种基本类型外,所有的类型都称为引用类型(数组,类,接口,字符串)
在弄清楚值类型与引用类型之后,最后一点就是值传递与引用传递,这才是关键!!!!!
[值传递] 基本数据类型赋值都属于值传递,值传递传递的是实实在在的变量值,是传递原参数的拷贝,值传递后,实参传递给形参的值,形参发生改变而不影响实参。
[引用传递] 引用类型之间赋值属于引用传递。引用传递传递的是对象的引用地址,也就是它的本身(自己最通俗的理解)。引用传递:传的是地址,就是将实参的地址传递给形参, 形参改变了,实参当然被改变了,因为他们指向相同的地址。
[内存分配]一个具有值类型(value type)的数据存放在栈内的一个变量中。即是在栈中分配内存空间,直接存储所包含的值,其值就代表数据本身。值类型的数据具有较快的存取速度。
一个具有引用类型(reference type)的数据并不驻留在栈中,而是存储于堆中。即是在堆中分配内存空间,不直接存储所包含的值,而是指向所要存储的值,其值代表的是所指向的地址。当访问一个具有引用类型的数据时,需要到栈中检查变量的内容,该变量引用堆中的一个实际数据。引用类型的数据比值类型的数据具有更大的存储规模和较低的访问速度。
【Java中有垃圾回收机制】
栈内存中的变量随着方法的结束内存自然销毁了,而用引用类型的时候,当方法结束的时候,这个对象可能被另一个引用类型所应用,不会销毁,只有当一个对象没有任何引用变量引用的时候,垃圾回收机制才会回收。
当一个堆内存中的对象没有被栈内存中表示地址的值“引用”时,这个对象就被称为垃圾对象,它无法被使用但却占据着内存中的区域,好比这样:
String s = new String(“person”); s = new String(“man”);
s本来是指向堆内存中值为person的对象的,但是s突然讨厌person了,它指向了堆内存中的man对象了,person就像一个孤儿一样被s遗弃了,但是person比孤儿还要惨,因为没有什么能找的到它,除了位高权重的‘垃圾回收器’,不过被当官的找到往往没什么好事,尤其是这个‘垃圾回收器’,它会豪不留情把‘垃圾’们清理走,并且无情的销毁,以便释放内存。
[装箱与拆箱]
其实装箱就是值类型到引用类型的转化过程。将一个值类型变量装箱成一个引用类型变量,首先会在托管堆上为新的引用类型变量分配内存空间,然后将值类型变量拷贝到托管堆上新分配的对象内存中,最后返回新分配的对象内存地址。装箱操作是可逆的,所以还有拆箱操作。拆箱操作获取只想对象中包含值类型部分的指针,然后由程序员手动将其对应的值拷贝给值类型变量。
public static void main(String[] args) {
String str="a";
StringBuffer sb=new StringBuffer("a");
process(str);
System.out.println(str);
process(sb);
System.out.println(sb);
process(str,sb);
System.out.println(str);
System.out.println(sb);
//结果 a a a aA
}
public static void process(String str) {
str = "A";
}
public static void process(StringBuffer sb) {
sb = new StringBuffer();
sb.append("A");
}
public static void process(String str, StringBuffer sb) {
str = new String("A");
sb.append("A");
}
问题:String,StringBuffer不都是引用类型吗,为什么代码运行的结果是a a a aA(没有变化)?
如果你认为引用类型在函数内修改值就一定能反映到外部,那只能说明你还没真正理解引用
第一个process,局部变量赋值,这只改变了局部变量的指向,并不能改变原来指向的String的内容
第二个process,同样的问题,给局部变量赋值,sb = new StringBuffer();以后sb就不是外部那个StringBuffer了,所以随便你怎么修改也不会反映到外部
第三个process,str = new String(“A”);和前面两个是一样的问题,而sb.append(“A”);是有效的,所以你看到最后输出了aA。
方法中的参数时局部变量来的,拿最后一个来说吧,方法public static void process(String str, StringBuffer sb) 中参数str和sb都是局部变量,调用process(str,sb),
是让局部变量跟传入的参数指向同一个对象,str = new String(“A”);只是将局部变量str指向另一个对象引用,跟外部的str没有关系,所以str仍为a,而sb.append(“A”);
是将局部变量sb指向的对象追加"A",而由于局部变量指向的对象跟外部的sb指向同一个对象,所以外部的sb也就变成aA了。