1.初始化與清理(Thinking in java學習一)

1. 用構造器來確保初始化

創建對象時,如果該類具有可用的構造器,java就會在用戶有能力操作對象之前自動調用相應的構造器,從而保證了初始化的進行。
Java中“初始化”與“創建”捆綁在一起的兩者不能分離。

問題1:構造器是一類特殊的方法,它沒有返回值。與返回值爲空(void)的區別?

  • 對於空值返回,儘管方法本身沒有返回什麼,但是仍然可以選擇讓它返回別的東西,但是構造器則不會返回任何東西,你別無選擇。

2.方法重載

  1. 區分重載方法
  • 每個重載的方法都必須有一個獨一無二的參數類型列表,參數相同,順序不同也能區分。(參數列表和順序的不同來區分
  • 每個重載的方法返回值類型有可能不一樣,僅返回值不同不能區分方法重載
  1. 涉及基本類型的重載
  • 傳入的實際參數類型小於方法中聲明的參數類型,實際參數類型就會被提升(向上自動轉換)。
  • 傳入的實際參數類型大於重載方法聲明的形式參數,如果不強制轉換的話,編譯器就會報錯。(向下強制轉換

3.默認構造器

沒有形式參數的構造方法--創建一個默認的構造器。如果類中沒有構造器,則編譯器會自動幫創建一個默認構造器。

4.關鍵字

  • this關鍵字

this關鍵字只能在方法內部使用,表示對調用方法的對象的引用。
注意:在方法內部調用同一個類的另外一個方法,就不必使用this,直接調用,當前方法中的this引用會自動應用於同一個類中的其他方法。

在構造器中調用構造器
使用this調用構造器,只能調用一個,不能調用兩個及以上,且必須將構造器調用置於最起始處。

  • static

static 的含義:
static修飾就是沒有this的方法,在static方法內部不能調用非靜態方法,反過來卻是可以的,且在沒有創建對象的前提下,僅僅通過類本身來調用static方法----static的主要用途。

5.清理:終結處理和垃圾回收

Java有垃圾回收器輔助回收無用對象佔據的內存資源。但是對象獲得了一塊“特殊”的內存區域,而垃圾回收器只會釋放由new分配的內存,所以它不會釋放該對象的內存。

finalize()方法工作原理

垃圾回收器準備好釋放對象佔用的存儲空間時,首先調用其finalize(),並且在下一次垃圾回收動作發生時,纔會真正回收對象佔用的內存。
A.對象可能不會被垃圾回收;
B.垃圾回收不等於“析構”;
C.垃圾回收只與內存相關;

finalize()意義和用途:

由於在分配內存時可能採用了類似C語言中的做法,而非java中的通常做法。這種情況主要發生在使用本地方法。是一種在Java中調用非Java代碼的方式。在非Java代碼中調用了C的malloc()函數系列來分配內存空間,除非調用free()函數,否則存儲空間將得不到釋放,從而造成內存泄露。此時需要在finalize()中用本地方法調用它。

要清理一個對象,用戶必須在需要清理的時刻執行清理動作的方法。無論是垃圾回收還有終結,都不一定會發生。如果Java虛擬機中並未面臨內存耗盡的情形,它是不會浪費時間去執行垃圾回收以恢復內存的。

終結條件

當對某個對象不再感興趣,也就是它可以被清理了,該對象應該處於某種狀態,使它佔用的內存可以被完全安全地釋放。

垃圾回收器工作原理

注:垃圾回收器對於提高對象的創建速度,卻具有明顯的效果。
注:在堆上分配的代價十分高昂。
自適應的、分代的、停止-複製、標記-清掃式垃圾回收器。

垃圾回收的意義:

在C++中,對象所佔的內存在程序結束運行之前一直被佔用,在明確釋放之前不能分配給其它對象;而在Java中,當沒有對象引用指向原先分配給某個對象的內存時,該內存便成爲垃圾。JVM的一個系統級線程會自動釋放該內存塊。垃圾回收意味着程序不再需要的對象是"無用信息",這些信息將被丟棄。當一個對象不再被引用的時候,內存回收它佔領的空間,以便空間被後來的新對象使用。事實上,除了釋放沒用的對象,垃圾回收也可以清除內存記錄碎片。由於創建對象和垃圾回收器釋放丟棄對象所佔的內存空間,內存會出現碎片。碎片是分配給對象的內存塊之間的空閒內存洞。碎片整理將所佔用的堆內存移到堆的一端,JVM將整理出的內存分配給新的對象。
垃圾回收能自動釋放內存空間,減輕編程的負擔。這使Java 虛擬機具有一些優點。首先,它能使編程效率提高。在沒有垃圾回收機制的時候,可能要花許多時間來解決一個難懂的存儲器問題。在用Java語言編程的時候,靠垃圾回收機制可大大縮短時間。其次是它保護程序的完整性, 垃圾回收是Java語言安全性策略的一個重要部份。
垃圾回收的一個潛在的缺點是它的開銷影響程序性能。Java虛擬機必須追蹤運行程序中有用的對象,而且最終釋放沒用的對象。這一個過程需要花費處理器的時間。其次垃圾回收算法的不完備性,早先採用的某些垃圾回收算法就不能保證100%收集到所有的廢棄內存。當然隨着垃圾回收算法的不斷改進以及軟硬件運行效率的不斷提升,這些問題都可以迎刃而解。

垃圾回收的算計分析

所謂根集就是正在執行的Java程序可以訪問的引用變量的集合(包括局部變量、參數、類變量),程序可以使用引用變量訪問對象的屬性和調用對象的方法。垃圾回收首先需要確定從根開始哪些是可達的和哪些是不可達的,從根集可達的對象都是活動對象,它們不能作爲垃圾被回收,這也包括從根集間接可達的對象。而根集通過任意路徑不可達的對象符合垃圾收集的條件,應該被回收。

  1. 引用計數法(Reference Counting Collector)
      
    引用計數法是唯一沒有使用根集的垃圾回收的法,該算法使用引用計數器來區分存活對象和不再使用的對象。一般來說,堆中的每個對象對應一個引用計數器。當每一次創建一個對象並賦給一個變量時,引用計數器置爲1。當對象被賦給任意變量時,引用計數器每次加1當對象出了作用域後(該對象丟棄不再使用),引用計數器減1,一旦引用計數器爲0,對象就滿足了垃圾收集的條件。
    基於引用計數器的垃圾收集器運行較快,不會長時間中斷程序執行,適宜地必須實時運行的程序。但引用計數器增加了程序執行的開銷,因爲每次對象賦給新的變量,計數器加1,而每次現有對象出了作用域生,計數器減1。

  2. tracing算法(Tracing Collector)

    tracing算法是爲了解決引用計數法的問題而提出,它使用了根集的概念。基於tracing算法的垃圾收集器從根集開始掃描,識別出哪些對象可達,哪些對象不可達,並用某種方式標記可達對象,例如對每個可達對象設置一個或多個位。在掃描識別過程中,基於tracing算法的垃圾收集也稱爲標記和清除(mark-and-sweep)垃圾收集器

  3. compacting算法(Compacting Collector)

    爲了解決堆碎片問題,基於tracing的垃圾回收吸收了Compacting算法的思想,在清除的過程中,算法將所有的對象移到堆的一端,堆的另一端就變成了一個相鄰的空閒內存區,收集器會對它移動的所有對象的所有引用進行更新,使得這些引用在新的位置能識別原來的對象。在基於Compacting算法的收集器的實現中,一般增加句柄和句柄表。

  4. copying算法(Coping Collector)

    該算法的提出是爲了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時把堆分成一個對象區和多個空閒區,程序從對象區爲對象分配空間,當對象滿了,基於coping算法的垃圾回收就從根集中掃描活動對象,並將每個活動對象複製到空閒區(使得活動對象所佔的內存之間沒有空閒間隔),這樣空閒區變成了對象區,原來的對象區變成了空閒區,程序會在新的對象區中分配內存。
      一種典型的基於coping算法的垃圾回收是stop-and-copy算法,它將堆分成對象區和空閒區域區,在對象區與空閒區域的切換過程中,程序暫停執行。

  5. generation算法(Generational Collector)
       stop-and-copy垃圾收集器的一個缺陷是收集器必須複製所有的活動對象,這增加了程序等待時間,這是coping算法低效的原因。在程序設計中有這樣的規律:多數對象存在的時間比較短,少數的存在時間比較長。因此,generation算法將堆分成兩個或多個,每個子堆作爲對象的一代 (generation)。由於多數對象存在的時間比較短,隨着程序丟棄不使用的對象,垃圾收集器將從最年輕的子堆中收集這些對象。在分代式的垃圾收集器運行後,上次運行存活下來的對象移到下一最高代的子堆中,由於老一代的子堆不會經常被回收,因而節省了時間。

  6. adaptive算法(Adaptive Collector)
      
    在特定的情況下,一些垃圾收集算法會優於其它算法。基於Adaptive算法的垃圾收集器就是監控當前堆的使用情況,並將選擇適當算法的垃圾收集器。

6.成員初始化

  • 類的每個基本類型數據成員保證都會有一個初始值。儘管有一些初值沒有給出,但它們確實有初值。
  • 指定初始化:在定義類成員變量的地方爲其賦值。

7.構造器初始化

可以用構造器來進行初始化。
注意:無法阻止自動初始化的進行,它將在構造器被調用之前發生。

  • 初始化順序
    在類的內部,類的定義先後順序決定了初始化的順序。

  • 靜態數據的初始化
    靜態數據的初始化和非靜態數據類似,但是初始化的順序是先靜態變量,後非靜態變量。

對象創建過程:(Dog類爲例子)
A.構造器沒有顯式的static關鍵字,單實際上就是靜態方法。首次創建類型爲Dog的對象時,或者Dog類的靜態方法、靜態域被訪問時,
Java解釋器必須查找類路徑,以定位Dog.class文件。
B.然後載入Dog.class,有關靜態初始化的所以動作都會執行。因此,靜態初始化只在Class對象首次加載的時候進行一次。
C.當用new Dog()創建對象的時候,首先將在堆上爲Dog對象分配足夠的存儲空間。
D.這塊存儲空間爲被清零,這就自動地將Dog對象中的所有基本數據類型都設置成了默認值,而引用則被設置成了null。
E.執行所有出現於字段定義處的初始化動作。
F.執行構造器。

  • 顯示的靜態初始化. 靜態語句塊:Java允許將多個靜態初始化動作組織成一個特殊的靜態語句塊。

  • 非靜態實例初始化
    對於非靜態初始化,用來初始化每個對象的非靜態變量。這種語法對於支持“匿名內部類”的初始化是必須的。

8.數組初始化

編譯器不允許指定數組的大小。
int[] a1;
現在擁有的只是對數組的一個引用,即內存已經分配了足夠大的存儲空間給該引用,並沒有給數據對象本身分配任何空間。

可變參數列表
Object...args,String...testString;
Java SE5後加入了可變參數列表的特性。

9.枚舉類型enum

在Java SE5中新增enum關鍵字,使得我們需要羣組並使用枚舉類型集時,可以方便地處理。
實用特性:它可以在switch語句內使用。
public enum SpecTest{A,B,C,D};
public class Burrito {
SpecTest degree;
switch(){
case A:break;
case B:break;
……
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章