引用類(lèi)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)過(guò)程
基本類(lèi)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)非常簡(jiǎn)單,引用類(lèi)型是把對(duì)象的地址放到棧內(nèi)存中,數(shù)據(jù)放在堆內(nèi)存中。在這通過(guò)幾個(gè)小程序簡(jiǎn)單描述一下引用類(lèi)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)過(guò)程:
class Person{
String name;
int age;
void say(){
System.out.println("姓名:"+name+",年齡:"+age);
}
}
public class Demo01{
public static void main(String args[]){
Person p1=new Person();
Person p2=new Person();
p1.name="張三";
p1.age=20;
p2=p1;
p1.say();
p2.say();
p2.name="李四";
p2.age=40;
p1.say();
p2.say();
}
}
上面的程序先新建了一個(gè)Person類(lèi),里面有兩個(gè)成員變量還有一個(gè)成員方法。然后創(chuàng)建了一個(gè)Demo01類(lèi)。執(zhí)行如下代碼:
Person p1=new Person;
Person p2=new Person();
就會(huì)為兩個(gè)Person實(shí)例對(duì)象分配內(nèi)存空間,將兩個(gè)對(duì)象初始化,內(nèi)存分配如圖1所示:
執(zhí)行
p1.name="張三";
p1.age=20;為實(shí)例對(duì)象p1賦值,內(nèi)存分布如圖2所示:
p2=p1;是將實(shí)例對(duì)象p2指向?qū)嵗龑?duì)象p1的內(nèi)存空間,原來(lái)為實(shí)例對(duì)象p1分配的內(nèi)存空間就會(huì)失去指向,這樣當(dāng)系統(tǒng)執(zhí)行垃圾(GC)技術(shù)時(shí)就會(huì)將這一部分內(nèi)存釋放。內(nèi)存分步如圖3所示:

執(zhí)行
p1.say();
p2.say();
就會(huì)輸出:
姓名:張三,年齡:20
姓名:張三,年齡:20
執(zhí)行
p2.name="李四";
p2.age=40;
就會(huì)將原先的值覆蓋,內(nèi)存分配如圖4所示:

執(zhí)行
p1.say();
p2.say();
就會(huì)輸出
姓名:李四,年齡:40
姓名:李四,年齡:40
這就是引用類(lèi)型數(shù)據(jù)的存儲(chǔ)過(guò)程。java程序采用這種存儲(chǔ)方式主要有兩個(gè)原因:
1.棧內(nèi)存存取速度非常快,僅次于寄存器。2.與垃圾回收機(jī)制(GC)相連,有利于機(jī)制刪除沒(méi)有指向的堆內(nèi)存數(shù)據(jù),釋放內(nèi)存空間。
上面的程序執(zhí)行
p2=p1;
這條語(yǔ)句后,將p2指向了p1所指向的數(shù)據(jù)并不能完成復(fù)制功能,我們可以稍作修改就可以完成復(fù)制功能,程序如下:
class Person{
String name;
int age;
void say(){
System.out.println("姓名:"+name+",年齡:"+age);
}
}
public class Demo02{
public static void main(String args[]){
Person p1=new Person();
Person p2=new Person();
p1.name="張三";
p1.age=20;
p2.name=p1.name;
p2.age=p1.age;
p1.say();
p2.say();
p2.name="李四";
p2.age=40;
p1.say();
p2.say();
}
}
這個(gè)程序的輸出結(jié)果是:
姓名:張三,年齡:20
姓名:張三,年齡:20
姓名:張三,年齡:20
姓名:李四,年齡:40
我們來(lái)分析它的內(nèi)存存儲(chǔ)過(guò)程,執(zhí)行代碼
Person p1=new Person();
Person p2=new Person();
p1.name="張三";
p1.age=20;
它的存儲(chǔ)過(guò)程如圖1和圖2相同,執(zhí)行代碼
p2.name=p1.name;
p2.age=p1.age;
它并沒(méi)有將p2指向p1所指向的數(shù)據(jù),而是將p1所指向的數(shù)據(jù)復(fù)制給p1所指向的數(shù)據(jù)。它的內(nèi)存分配過(guò)程如圖5所示:

執(zhí)行代碼
p1.say();
p2.say();
就會(huì)輸出
姓名:張三,年齡:20
姓名:張三,年齡:20
執(zhí)行代碼
p2.name="李四";
p2.age=40;
修改了p2所指向的數(shù)據(jù)的值,但沒(méi)有修改p1所指向的數(shù)據(jù)的值。內(nèi)存分配過(guò)程如圖6所示:

執(zhí)行代碼
p1.say();
p2.say();
就會(huì)輸出
姓名:張三,年齡:20
姓名:李四,年齡:40
下面我們看下一個(gè)程序
class Person{
String name;
int age;
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return name;
}
public int age(){
return age;
}
public void say(){
System.out.println("姓名:"+name+",年齡:"+age);
}
}
public class Demo03{
public static void main(String args[]){
Person[] per=new Person[2];
per[0]=new Person();
per[1]=new Person();
per[0].setName("張三");
per[0].setAge(20);
per[1].setName("李四");
per[1].setAge(40);
for(int i=0;i<per.length;i++){
per[i].say();
}
}
}
上面的程序輸出結(jié)果為
姓名:張三,年齡:20
姓名:李四,年齡:40
此程序首先建立一個(gè)Person類(lèi),里面有成員變量和成員方法,然后定義一個(gè)Demo03類(lèi),執(zhí)行代碼
Person[] per=new Person[2];
per[0]=new Person();
per[1]=new Person();
建立一個(gè)Person對(duì)象的數(shù)組并初始化,這里的初始化只是將數(shù)組元素指向null,而并沒(méi)有在堆內(nèi)存中分配空間,內(nèi)存存儲(chǔ)如圖7所示:

執(zhí)行代碼
per[0]=new Person();
per[1]=new Person();
這才是為數(shù)組元素開(kāi)辟了堆內(nèi)存空間并初始化,如圖8所示:

執(zhí)行代碼
per[0].setName("張三");
per[0].setAge(20);
per[1].setName("李四");
per[1].setAge(40);
將張數(shù)據(jù)存儲(chǔ)到各個(gè)數(shù)組元素所指向的堆內(nèi)存中,如圖9所示:

執(zhí)行代碼
for(int i=0;i<per.length;i++){
per[i].say();
}
是將數(shù)組中的值輸出出來(lái),就會(huì)輸出以上輸出結(jié)果。
java引用類(lèi)型的存儲(chǔ)過(guò)程就是這樣。這只是在下的一個(gè)小見(jiàn)解,可能有不到位或不
正確的地方,歡迎各位朋友提出見(jiàn)解,共同分享知識(shí)。
posted on 2010-10-13 08:26 馮魁 閱讀(823) 評(píng)論(2) 編輯 收藏