1. 用構(gòu)造器來確保初始化
創(chuàng)建對象時,如果該類具有可用的構(gòu)造器,java就會在用戶有能力操作對象之前自動調(diào)用相應(yīng)的構(gòu)造器,從而保證了初始化的進(jìn)行。
Java中“初始化”與“創(chuàng)建”捆綁在一起的兩者不能分離。
問題1:構(gòu)造器是一類特殊的方法,它沒有返回值。與返回值為空(void)的區(qū)別?
- 對于空值返回,盡管方法本身沒有返回什么,但是仍然可以選擇讓它返回別的東西,但是構(gòu)造器則不會返回任何東西,你別無選擇。
2.方法重載
- 區(qū)分重載方法
- 每個重載的方法都必須有一個獨(dú)一無二的參數(shù)類型列表,參數(shù)相同,順序不同也能區(qū)分。(參數(shù)列表和順序的不同來區(qū)分)
- 每個重載的方法返回值類型有可能不一樣,僅返回值不同不能區(qū)分方法重載。
- 涉及基本類型的重載
- 傳入的實(shí)際參數(shù)類型小于方法中聲明的參數(shù)類型,實(shí)際參數(shù)類型就會被提升(向上自動轉(zhuǎn)換)。
- 傳入的實(shí)際參數(shù)類型大于重載方法聲明的形式參數(shù),如果不強(qiáng)制轉(zhuǎn)換的話,編譯器就會報(bào)錯。(向下強(qiáng)制轉(zhuǎn)換)
3.默認(rèn)構(gòu)造器
沒有形式參數(shù)的構(gòu)造方法--創(chuàng)建一個默認(rèn)的構(gòu)造器。如果類中沒有構(gòu)造器,則編譯器會自動幫創(chuàng)建一個默認(rèn)構(gòu)造器。
4.關(guān)鍵字
- this關(guān)鍵字
this關(guān)鍵字只能在方法內(nèi)部使用,表示對調(diào)用方法的對象的引用。
注意:在方法內(nèi)部調(diào)用同一個類的另外一個方法,就不必使用this,直接調(diào)用,當(dāng)前方法中的this引用會自動應(yīng)用于同一個類中的其他方法。
在構(gòu)造器中調(diào)用構(gòu)造器
使用this調(diào)用構(gòu)造器,只能調(diào)用一個,不能調(diào)用兩個及以上,且必須將構(gòu)造器調(diào)用置于最起始處。
- static
static 的含義:
static修飾就是沒有this的方法,在static方法內(nèi)部不能調(diào)用非靜態(tài)方法,反過來卻是可以的,且在沒有創(chuàng)建對象的前提下,僅僅通過類本身來調(diào)用static方法----static的主要用途。
5.清理:終結(jié)處理和垃圾回收
Java有垃圾回收器輔助回收無用對象占據(jù)的內(nèi)存資源。但是對象獲得了一塊“特殊”的內(nèi)存區(qū)域,而垃圾回收器只會釋放由new分配的內(nèi)存,所以它不會釋放該對象的內(nèi)存。
finalize()方法工作原理:
垃圾回收器準(zhǔn)備好釋放對象占用的存儲空間時,首先調(diào)用其finalize(),并且在下一次垃圾回收動作發(fā)生時,才會真正回收對象占用的內(nèi)存。
A.對象可能不會被垃圾回收;
B.垃圾回收不等于“析構(gòu)”;
C.垃圾回收只與內(nèi)存相關(guān);
finalize()意義和用途:
由于在分配內(nèi)存時可能采用了類似C語言中的做法,而非java中的通常做法。這種情況主要發(fā)生在使用本地方法。是一種在Java中調(diào)用非Java代碼的方式。在非Java代碼中調(diào)用了C的malloc()函數(shù)系列來分配內(nèi)存空間,除非調(diào)用free()函數(shù),否則存儲空間將得不到釋放,從而造成內(nèi)存泄露。此時需要在finalize()中用本地方法調(diào)用它。
要清理一個對象,用戶必須在需要清理的時刻執(zhí)行清理動作的方法。無論是垃圾回收還有終結(jié),都不一定會發(fā)生。如果Java虛擬機(jī)中并未面臨內(nèi)存耗盡的情形,它是不會浪費(fèi)時間去執(zhí)行垃圾回收以恢復(fù)內(nèi)存的。
終結(jié)條件
當(dāng)對某個對象不再感興趣,也就是它可以被清理了,該對象應(yīng)該處于某種狀態(tài),使它占用的內(nèi)存可以被完全安全地釋放。
垃圾回收器工作原理
注:垃圾回收器對于提高對象的創(chuàng)建速度,卻具有明顯的效果。
注:在堆上分配的代價十分高昂。
自適應(yīng)的、分代的、停止-復(fù)制、標(biāo)記-清掃式垃圾回收器。
垃圾回收的意義:
在C++中,對象所占的內(nèi)存在程序結(jié)束運(yùn)行之前一直被占用,在明確釋放之前不能分配給其它對象;而在Java中,當(dāng)沒有對象引用指向原先分配給某個對象的內(nèi)存時,該內(nèi)存便成為垃圾。JVM的一個系統(tǒng)級線程會自動釋放該內(nèi)存塊。垃圾回收意味著程序不再需要的對象是"無用信息",這些信息將被丟棄。當(dāng)一個對象不再被引用的時候,內(nèi)存回收它占領(lǐng)的空間,以便空間被后來的新對象使用。事實(shí)上,除了釋放沒用的對象,垃圾回收也可以清除內(nèi)存記錄碎片。由于創(chuàng)建對象和垃圾回收器釋放丟棄對象所占的內(nèi)存空間,內(nèi)存會出現(xiàn)碎片。碎片是分配給對象的內(nèi)存塊之間的空閑內(nèi)存洞。碎片整理將所占用的堆內(nèi)存移到堆的一端,JVM將整理出的內(nèi)存分配給新的對象。
垃圾回收能自動釋放內(nèi)存空間,減輕編程的負(fù)擔(dān)。這使Java 虛擬機(jī)具有一些優(yōu)點(diǎn)。首先,它能使編程效率提高。在沒有垃圾回收機(jī)制的時候,可能要花許多時間來解決一個難懂的存儲器問題。在用Java語言編程的時候,靠垃圾回收機(jī)制可大大縮短時間。其次是它保護(hù)程序的完整性, 垃圾回收是Java語言安全性策略的一個重要部份。
垃圾回收的一個潛在的缺點(diǎn)是它的開銷影響程序性能。Java虛擬機(jī)必須追蹤運(yùn)行程序中有用的對象,而且最終釋放沒用的對象。這一個過程需要花費(fèi)處理器的時間。其次垃圾回收算法的不完備性,早先采用的某些垃圾回收算法就不能保證100%收集到所有的廢棄內(nèi)存。當(dāng)然隨著垃圾回收算法的不斷改進(jìn)以及軟硬件運(yùn)行效率的不斷提升,這些問題都可以迎刃而解。
垃圾回收的算計(jì)分析:
所謂根集就是正在執(zhí)行的Java程序可以訪問的引用變量的集合(包括局部變量、參數(shù)、類變量),程序可以使用引用變量訪問對象的屬性和調(diào)用對象的方法。垃圾回收首先需要確定從根開始哪些是可達(dá)的和哪些是不可達(dá)的,從根集可達(dá)的對象都是活動對象,它們不能作為垃圾被回收,這也包括從根集間接可達(dá)的對象。而根集通過任意路徑不可達(dá)的對象符合垃圾收集的條件,應(yīng)該被回收。
引用計(jì)數(shù)法(Reference Counting Collector)
引用計(jì)數(shù)法是唯一沒有使用根集的垃圾回收的法,該算法使用引用計(jì)數(shù)器來區(qū)分存活對象和不再使用的對象。一般來說,堆中的每個對象對應(yīng)一個引用計(jì)數(shù)器。當(dāng)每一次創(chuàng)建一個對象并賦給一個變量時,引用計(jì)數(shù)器置為1。當(dāng)對象被賦給任意變量時,引用計(jì)數(shù)器每次加1當(dāng)對象出了作用域后(該對象丟棄不再使用),引用計(jì)數(shù)器減1,一旦引用計(jì)數(shù)器為0,對象就滿足了垃圾收集的條件。
基于引用計(jì)數(shù)器的垃圾收集器運(yùn)行較快,不會長時間中斷程序執(zhí)行,適宜地必須實(shí)時運(yùn)行的程序。但引用計(jì)數(shù)器增加了程序執(zhí)行的開銷,因?yàn)槊看螌ο筚x給新的變量,計(jì)數(shù)器加1,而每次現(xiàn)有對象出了作用域生,計(jì)數(shù)器減1。-
tracing算法(Tracing Collector)
tracing算法是為了解決引用計(jì)數(shù)法的問題而提出,它使用了根集的概念。基于tracing算法的垃圾收集器從根集開始掃描,識別出哪些對象可達(dá),哪些對象不可達(dá),并用某種方式標(biāo)記可達(dá)對象,例如對每個可達(dá)對象設(shè)置一個或多個位。在掃描識別過程中,基于tracing算法的垃圾收集也稱為標(biāo)記和清除(mark-and-sweep)垃圾收集器
-
compacting算法(Compacting Collector)
為了解決堆碎片問題,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的過程中,算法將所有的對象移到堆的一端,堆的另一端就變成了一個相鄰的空閑內(nèi)存區(qū),收集器會對它移動的所有對象的所有引用進(jìn)行更新,使得這些引用在新的位置能識別原來的對象。在基于Compacting算法的收集器的實(shí)現(xiàn)中,一般增加句柄和句柄表。
-
copying算法(Coping Collector)
該算法的提出是為了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時把堆分成一個對象區(qū)和多個空閑區(qū),程序從對象區(qū)為對象分配空間,當(dāng)對象滿了,基于coping算法的垃圾回收就從根集中掃描活動對象,并將每個活動對象復(fù)制到空閑區(qū)(使得活動對象所占的內(nèi)存之間沒有空閑間隔),這樣空閑區(qū)變成了對象區(qū),原來的對象區(qū)變成了空閑區(qū),程序會在新的對象區(qū)中分配內(nèi)存。
一種典型的基于coping算法的垃圾回收是stop-and-copy算法,它將堆分成對象區(qū)和空閑區(qū)域區(qū),在對象區(qū)與空閑區(qū)域的切換過程中,程序暫停執(zhí)行。 generation算法(Generational Collector)
stop-and-copy垃圾收集器的一個缺陷是收集器必須復(fù)制所有的活動對象,這增加了程序等待時間,這是coping算法低效的原因。在程序設(shè)計(jì)中有這樣的規(guī)律:多數(shù)對象存在的時間比較短,少數(shù)的存在時間比較長。因此,generation算法將堆分成兩個或多個,每個子堆作為對象的一代 (generation)。由于多數(shù)對象存在的時間比較短,隨著程序丟棄不使用的對象,垃圾收集器將從最年輕的子堆中收集這些對象。在分代式的垃圾收集器運(yùn)行后,上次運(yùn)行存活下來的對象移到下一最高代的子堆中,由于老一代的子堆不會經(jīng)常被回收,因而節(jié)省了時間。adaptive算法(Adaptive Collector)
在特定的情況下,一些垃圾收集算法會優(yōu)于其它算法。基于Adaptive算法的垃圾收集器就是監(jiān)控當(dāng)前堆的使用情況,并將選擇適當(dāng)算法的垃圾收集器。
6.成員初始化
- 類的每個基本類型數(shù)據(jù)成員保證都會有一個初始值。盡管有一些初值沒有給出,但它們確實(shí)有初值。
- 指定初始化:在定義類成員變量的地方為其賦值。
7.構(gòu)造器初始化
可以用構(gòu)造器來進(jìn)行初始化。
注意:無法阻止自動初始化的進(jìn)行,它將在構(gòu)造器被調(diào)用之前發(fā)生。
初始化順序
在類的內(nèi)部,類的定義先后順序決定了初始化的順序。靜態(tài)數(shù)據(jù)的初始化
靜態(tài)數(shù)據(jù)的初始化和非靜態(tài)數(shù)據(jù)類似,但是初始化的順序是先靜態(tài)變量,后非靜態(tài)變量。
對象創(chuàng)建過程:(Dog類為例子)
A.構(gòu)造器沒有顯式的static關(guān)鍵字,單實(shí)際上就是靜態(tài)方法。首次創(chuàng)建類型為Dog的對象時,或者Dog類的靜態(tài)方法、靜態(tài)域被訪問時,
Java解釋器必須查找類路徑,以定位Dog.class文件。
B.然后載入Dog.class,有關(guān)靜態(tài)初始化的所以動作都會執(zhí)行。因此,靜態(tài)初始化只在Class對象首次加載的時候進(jìn)行一次。
C.當(dāng)用new Dog()創(chuàng)建對象的時候,首先將在堆上為Dog對象分配足夠的存儲空間。
D.這塊存儲空間為被清零,這就自動地將Dog對象中的所有基本數(shù)據(jù)類型都設(shè)置成了默認(rèn)值,而引用則被設(shè)置成了null。
E.執(zhí)行所有出現(xiàn)于字段定義處的初始化動作。
F.執(zhí)行構(gòu)造器。
顯示的靜態(tài)初始化. 靜態(tài)語句塊:Java允許將多個靜態(tài)初始化動作組織成一個特殊的靜態(tài)語句塊。
非靜態(tài)實(shí)例初始化
對于非靜態(tài)初始化,用來初始化每個對象的非靜態(tài)變量。這種語法對于支持“匿名內(nèi)部類”的初始化是必須的。
8.數(shù)組初始化
編譯器不允許指定數(shù)組的大小。
int[] a1;
現(xiàn)在擁有的只是對數(shù)組的一個引用,即內(nèi)存已經(jīng)分配了足夠大的存儲空間給該引用,并沒有給數(shù)據(jù)對象本身分配任何空間。
可變參數(shù)列表
Object...args,String...testString;
Java SE5后加入了可變參數(shù)列表的特性。
9.枚舉類型enum
在Java SE5中新增enum關(guān)鍵字,使得我們需要群組并使用枚舉類型集時,可以方便地處理。
實(shí)用特性:它可以在switch語句內(nèi)使用。
public enum SpecTest{A,B,C,D};
public class Burrito {
SpecTest degree;
switch(){
case A:break;
case B:break;
……
}
}