本章目標(biāo)
- 掌握J(rèn)ava中的內(nèi)存劃分
- 初窺Java引用傳遞
- 垃圾的產(chǎn)生分析
內(nèi)存劃分:對(duì)象創(chuàng)建之初
public class ClassDemo02{
public static void main(String args[]){
Person per = new Person() ; // 創(chuàng)建并實(shí)例化對(duì)象
}
}
Person per = new Person();
- 聲明對(duì)象:Person per, 棧內(nèi)存中聲明,與數(shù)組一樣,數(shù)組名稱(chēng)就保存在棧內(nèi)存中,只開(kāi)辟了 棧內(nèi)存的對(duì)象是無(wú)法使用的,必須有其堆內(nèi)存的引用才可以使用。
-
實(shí)例化對(duì)象:new Person(),在堆中開(kāi)辟空間,所有的內(nèi)容都是默認(rèn)值。
- String:是一個(gè)字符串,本身是一個(gè)類(lèi),就是一個(gè)引用數(shù)據(jù)類(lèi)型,則此時(shí)默認(rèn)值就是null。
- int:是一個(gè)整數(shù),本身是一個(gè)數(shù),所以是基本數(shù)據(jù)類(lèi)型,則此時(shí)的默認(rèn)值就是0。
如果進(jìn)一步劃分以上的代碼,則可以寫(xiě)成如下的形式:
Person per = null ; // 聲明對(duì)象
per = new Person() ; // 實(shí)例化對(duì)象
開(kāi)發(fā)中,數(shù)據(jù)最好賦一個(gè)初值,這樣操作會(huì)比較方便。
了解了其分配關(guān)系,就可以為屬性賦值,并調(diào)用類(lèi)中的方法。
使用格式:
- 調(diào)用屬性:對(duì)象.屬性
- 調(diào)用方法:對(duì)象.方法()
class Person{
String name ; // 聲明姓名屬性
int age ; // 聲明年齡屬性
public void tell(){ // 取得信息
System.out.println("姓名:" + name + ",年齡:" + age) ;
}
};
public class ClassDemo03{
public static void main(String args[]){
Person per = null ; // 聲明對(duì)象
per = new Person() ; // 實(shí)例化對(duì)象
per.name = "張三" ; // 為姓名賦值
per.age = 30 ; // 為年齡賦值
per.tell() ; // 調(diào)用方法,打印信息
}
};
輸出結(jié)果:
姓名:張三,年齡:30
此時(shí),內(nèi)容顯示出來(lái)后,實(shí)際上所有的操作都是要在內(nèi)存中直接體現(xiàn)出來(lái)的。
問(wèn)題:
對(duì)象是保存在棧內(nèi)存之中的,屬性是保存在堆內(nèi)存之中的,那么方法呢?
在程序中,所有方法是保存在全局代碼區(qū)之中的。此區(qū)域中的內(nèi)容是共享的。
注意:
在使用對(duì)象的時(shí)候,對(duì)象必須被實(shí)例化之后才可以使用(實(shí)例化對(duì)象,并不單單指的是通過(guò)new關(guān)鍵字實(shí)現(xiàn)的,只要有堆內(nèi)存的空間指向,則就表示實(shí)例化成功。)
如果不實(shí)例化會(huì)如何呢?
Exception in thread "main" java.lang.NullPointerException
at ClassDemo03 main(ClassDemo03.java:12)
此時(shí)出現(xiàn)了一個(gè)空指向異常。
在引用操作中,如果一個(gè)對(duì)象沒(méi)有堆內(nèi)存的引用,而調(diào)用了類(lèi)中的屬性或方法,就會(huì)出現(xiàn)此問(wèn)題。
那么既然可以產(chǎn)生一個(gè)對(duì)象,能不能產(chǎn)生多個(gè)對(duì)象呢?
可以,只要按照操作格式完成即可。
class Person{
String name ; // 聲明姓名屬性
int age ; // 聲明年齡屬性
public void tell(){ // 取得信息
System.out.println("姓名:" + name + ",年齡:" + age) ;
}
};
public class ClassDemo04{
public static void main(String args[]){
Person per1 = null ; // 聲明per1對(duì)象
Person per2 = null ; // 聲明per2對(duì)象
per1 = new Person() ; // 實(shí)例化per1對(duì)象
per2 = new Person() ; // 實(shí)例化per2對(duì)象
per1.name = "張三" ; // 設(shè)置per1中的name屬性?xún)?nèi)容
per1.age = 30 ; // 設(shè)置per1中的age屬性?xún)?nèi)容
per2.name = "李四" ; // 設(shè)置per2中的name屬性?xún)?nèi)容
per2.age = 33 ; // 設(shè)置per2中的age屬性?xún)?nèi)容
System.out.print("per1對(duì)象中的內(nèi)容 --> ") ;
per1.tell() ; // 調(diào)用類(lèi)中的方法
System.out.print("per2對(duì)象中的內(nèi)容 --> ") ;
per2.tell() ; // 調(diào)用類(lèi)中的方法
}
};
輸出結(jié)果:
per1對(duì)象中的內(nèi)容 --> 姓名:張三,年齡:30
per2對(duì)象中的內(nèi)容 --> 姓名:李四,年齡:33
類(lèi)是引用數(shù)據(jù)類(lèi)型,那么這些是如何引用的呢?
所謂的引用數(shù)據(jù)類(lèi)型,實(shí)際上就是傳遞的就是是堆內(nèi)存的使用權(quán),可以同時(shí)為一個(gè)堆內(nèi)存空間定義多個(gè)棧內(nèi)存的引用操作 。
class Person{
String name ; // 聲明姓名屬性
int age ; // 聲明年齡屬性
public void tell(){ // 取得信息
System.out.println("姓名:" + name + ",年齡:" + age) ;
}
};
public class ClassDemo05{
public static void main(String args[]){
Person per1 = null ; // 聲明per1對(duì)象
Person per2 = null ; // 聲明per2對(duì)象
per1 = new Person() ; // 只實(shí)例化per1一個(gè)對(duì)象
per2 = per1 ; // 把per1的堆內(nèi)存空間使用權(quán)給per2
per1.name = "張三" ; // 設(shè)置per1中的name屬性?xún)?nèi)容
per1.age = 30 ; // 設(shè)置per1中的age屬性?xún)?nèi)容
// 設(shè)置per2對(duì)象的內(nèi)容,實(shí)際上就是設(shè)置per1對(duì)象的內(nèi)容
per2.age = 33 ; // 設(shè)置per2中的age屬性?xún)?nèi)容
System.out.print("per1對(duì)象中的內(nèi)容 --> ") ;
per1.tell() ; // 調(diào)用類(lèi)中的方法
System.out.print("per2對(duì)象中的內(nèi)容 --> ") ;
per2.tell() ; // 調(diào)用類(lèi)中的方法
}
};
輸出結(jié)果:
per1對(duì)象中的內(nèi)容 --> 姓名:張三,年齡:33
per2對(duì)象中的內(nèi)容 --> 姓名:張三,年齡:33
再看一道引用傳遞的程序。
class Person{
String name ; // 聲明姓名屬性
int age ; // 聲明年齡屬性
public void tell(){ // 取得信息
System.out.println("姓名:" + name + ",年齡:" + age) ;
}
};
public class ClassDemo06{
public static void main(String args[]){
Person per1 = null ; // 聲明per1對(duì)象
Person per2 = null ; // 聲明per2對(duì)象
per1 = new Person() ; // 實(shí)例化per1對(duì)象
per2 = new Person() ; // 實(shí)例化per2對(duì)象
per1.name = "張三" ; // 設(shè)置per1中的name屬性?xún)?nèi)容
per1.age = 30 ; // 設(shè)置per1中的age屬性?xún)?nèi)容
per2.name = "李四" ;
per2.age = 33 ; // 設(shè)置per2中的age屬性?xún)?nèi)容
per2 = per1 ; // 把per1的堆內(nèi)存空間使用權(quán)給per2
System.out.print("per1對(duì)象中的內(nèi)容 --> ") ;
per1.tell() ; // 調(diào)用類(lèi)中的方法
System.out.print("per2對(duì)象中的內(nèi)容 --> ") ;
per2.tell() ; // 調(diào)用類(lèi)中的方法
}
};
輸出結(jié)果:
per1對(duì)象中的內(nèi)容 --> 姓名:張三,年齡:30
per2對(duì)象中的內(nèi)容 --> 姓名:張三,年齡:30
因?yàn)閜er2改變了指向,所以其原本的內(nèi)存空間就沒(méi)有任何棧的引用,則這樣的內(nèi)存就被稱(chēng)為垃圾,等待著垃圾收集機(jī)制進(jìn)行回收。
GC垃圾收集機(jī)制的簡(jiǎn)稱(chēng)。
總結(jié)
1、掌握棧與堆內(nèi)存的關(guān)系
2、對(duì)象保存在棧內(nèi)存之中,而具體內(nèi)容保存在堆內(nèi)存之中
3、對(duì)象間的引用傳遞,實(shí)際上傳遞的就是堆內(nèi)存空間的使用權(quán)
4、垃圾的產(chǎn)生。