隨著計算機革命的發展,“不安全”的編程方式已逐漸成為編程代價高昂的主因之一。
初始化和清理正是涉及安全的兩個問題。
1.用構造器確保初始化
默認構造器(無參構造器):不接受任何參數的構造器
2.方法重載
1.區分重載方法
每個重載的方法都必須有一個獨一無二的參數類型列表。
參數順序的不同也足以區分兩個方法。不過,一般情況下,別這麼做,因為這會使代碼難以維護。
2.涉及基本類型的重載
基本類型能從一個“較小”的類型自動提升至一個“較大”的類型,此過程一旦牽涉到重載,可能會造成一些混淆。
如果傳入的數據類型(實際參數類型)小於方法中聲明的形式參數類型,實際數據就會被提升。char型略有不同,
如果無法找到恰好接受char參數的方法,就會把char直接提升至int型。
如果傳入的實際參數較大,就得通過類型轉換來執行窄化轉換。如果不這樣做,編譯器就會報錯。
3.以返回值區分重載方法
有時調用方法而忽略其返回值,所以根據返回值區分重載方法是行不通的。、
3.默認構造器
如果類中沒有構造器,則編譯器會自動幫你創建一個默認構造器。但是,如果已經定義了一個構造器(無論是否有參數),編譯器就不會幫你自動創建默認構造器。
4.this關鍵字
this關鍵字只能在方法內部使用,表示對“調用方法的那個對象”的引用。
1.在構造器中調用構造器
在構造器中,如果為this添加了參數列表,那麼就有了不同的含義。這將產生對符合此參數列表的某個構造器的明確調用。
盡管可以用this調用一個構造器,但卻不能調用兩個。此外,必須將構造器調用置於最起始處,否則編譯器會報錯。
2.static的含義
static方法(靜態方法)就是沒有this的方法。可以在沒有創建任何對象的前提下,通過類本身調用static方法。具有全局函數的語義。
在static方法的內部不能調用非靜態方法,但是在非靜態方法中可以調用static方法。
5.清理:終結處理和垃圾回收
Java有垃圾回收器負責回收無用對象占據的內存資源。但也有特殊的情況:假定你的對象(並非使用new)獲得了一塊“特殊”的內存區域,由於垃圾
回收器只知道釋放那些經由new分配的內存,所以它不知道該如何釋放該對象的這塊“特殊”內存。為了應對這種情況,Java允許在類中定義一個名為finalize()的方法。
它的工作原理“假定”是這樣的:一旦垃圾回收器准備好釋放對象占用的存儲空間,將首先調用其finalize()方法,並且在下一次垃圾回收動作發生
時,才會真正回收對象占用的內存。所以要是你打算用finalize(),就能在垃圾回收時刻做一些重要的清理工作。
注意:finalize()與C++中的析構函數不同:在C++中,對象一定會被銷毀(如果程序中沒有缺陷的話),而Java裡的對象卻並非總是被垃圾回收。
換句話說:1.對象可能不被垃圾回收 2.垃圾回收並不等於“析構”
只要程序沒有瀕臨存儲空間用完的那一刻,對象占用的空間就總也得不到釋放。如果程序執行結束,並且垃圾回收器一直都沒有釋放你創建的任何
對象的存儲空間,則隨著程序的退出,那些資源也會全部交還給操作系統。這個策略是恰當的,因為垃圾回收本身也有開銷,要是不使用它,那就不用
支付這部分開銷了。
1.finalize()的用途何在
垃圾回收只與內存有關。使用垃圾回收器的唯一原因是為了回收程序不再使用的內存。所以對於與垃圾回收有關的任何行為來說(尤其是finalize()方法),
它們也必須同內存及其回收有關。
finalize()作用:釋放那些通過某種創建對象以外的方式為對象分配的存儲空間。
之所以要有finalize(),是由於在分配內存時可能采用了類似C語言中的做法,而非Java中通常做法。這種情況主要發生在使用“本地方法”的情況下,本地
方法是一種在Java中調用非Java代碼的方式。本地方法目前只支持C和C++,但C和C++可以調用其他語言寫的代碼,所以實際上可以調用任何代碼。
2.你必須實施清理
要清理一個對象,用戶必須在需要清理的時刻調用執行清理動作的方法。
垃圾回收器的存在並不能完全代替析構函數(而且絕對不能直接調用finalize()),如果希望進行除釋放存儲空間之外的清理工作,還是得明確調用某個
恰當的方法。
記住:無論是“垃圾回收”還是“finalize()”,都不保證一定會發生。如果Java虛擬機(JVM)並未面臨內存耗盡的情形,它是不會浪費時間去執行垃圾回收
以恢復內存的。
3.終結條件
通常,不能指望finalize(),必須創建其他的“清理”方法,並且明確的調用它們。
但是可以用finalize()驗證終結條件。在垃圾回收之前,只要對象存在沒有被適當的清理的部分,finalize()可以最終發現這種情況。
System.gc()用於強制進行終結動作。
4.垃圾回收器是如何工作的
在以前所用過的程序語言中,在堆上分配對象是非常昂貴的,你可能會覺得Java中所有對象都在堆上分配的方式也非常昂貴。然而垃圾回收器對於
提高對象的創建的速度,卻有非常明顯的效果。Java從堆上分配空間的速度,可以和其他語言從堆棧上分配空間的速度相媲美。
在某些Java虛擬機中,堆就像一個傳送帶,每分配一個新對象,它就往前移動一格,對象存儲空間的分配速度非常快。但Java中堆未必完全像傳送帶
那樣工作,要是那樣的話,勢必導致頻繁的內存頁面調度。然而垃圾回收器的介入,當它工作時,將一面回收空間,一面使堆中的對象緊湊排列。
其他系統中的垃圾回收機制:引用計數是一種簡單但速度很慢的垃圾回收技術。(當對象被引用時,引用計數加1,當離開或被置空時,引用計數減1,
當某個對象的引用計數為0時,就釋放其占用的空間)
在一些更快的模式中,垃圾回收器並不基於引用計數技術。它們依靠的思想是:對任何“活”的對象,一定能最終追溯到其存活在堆棧或靜態存儲區中的
引用。因此,如果從堆棧和靜態存儲區開始,遍歷所有的引用,就能找到所有“活”的對象。,沒有找到的對象就被自動回收。
Java虛擬機采用一種只適應的垃圾回收技術。
“停止-復制”:先暫停程序的運行,然後將所有活的對象從當前堆復制到另一個堆,沒有被復制的全部都是垃圾。當對象被復制到新堆時,它們是一個挨一個的,
所以新堆保持緊湊排列。“復制式回收器”效率會降低。原因:1.需要兩個分離的堆,維護比實際多一倍的空間。2。復制問題,程序進入穩定狀態後,可能只會產生
少量的垃圾,甚至沒有垃圾。復制式回收器仍然會將所有內存自一處復制到另一處,這很浪費。為了避免這種情況,一些Java虛擬機會進行檢查:要是沒有新垃圾
產生就轉換到另一種工作模式--“標記-清掃”。
“標記-清掃”:思路是從堆棧和靜態存儲區出發,遍歷所有的引用,進而找出所有存活的對象,然後設一個標記,全部標記工作完成,開始清理沒有標記的對象。
不會發生任何復制動作,所以剩下的堆空間是不連續的,垃圾回收器要是希望得到連續的空間,就得重新整理剩下的對象。
垃圾回收器根據不同的情況,調用不同的垃圾回收模式,這將是“自適應”技術。“自適應的、分代的、停止-復制、標記-清掃”式垃圾回收器。
6.成員初始化
Java盡力保證:所有變量在使用前都能得到恰當的初始化。對於方法的局部變量,Java以編譯時錯誤的形式來貫徹這種保證。
如果類的數據成員是基本類型,都會有一個默認的初始值。
1.指定初始化
如果想給某個變量賦初值,就直接的方法是,在定義時直接賦值。
也可以調用某個方法來提供初始值。
7.構造器初始化
可以用構造器來進行初始化,但是:無法阻止自動初始化的進行,它將在構造器被調用之前發生。
1.初始化順序
在類的內部,變量定義的先後順序決定了初始化的順序。即使變量定義散布於方法定義之間,它們仍舊會在任何方法(包括構造器)被調用之前得到初始化。
2.靜態數據的初始化
無論創建多少個對象,靜態數據都只占用一份存儲區域。
靜態初始化只有在必要的時刻才會進行。
3.顯式的靜態初始化
Java允許將多個靜態初始化動作組織成一個特殊的“靜態子句”(靜態塊)
static int i; static { i=45; } 4.非靜態實例初始化 int a; int b; { a = 1; b = 2; }
查看本欄目
與靜態初始化子句一模一樣,只不過少了static關鍵字。8.數組的初始化
數組只是相同類型的,用一個標識符名稱封裝到一起的一個對象序列或基本類型數據序列。
數組是通過方括號下標操作符[]來定義和使用的。
int[] arrInt = {1,2,3,4,5}; 或 int arrInt[];
arrInt.length:獲得數組內包含了多少個元素
Arrays.toString():屬於java.util標准庫,它將產生一維數組的可打印版本。
1.可變參數列表
public void printArray(Object[] args);
public void method(int... arrInt);9.枚舉類型
enum關鍵字,它使得我們在需要群組並使用枚舉類型集時,可以方便地處理。
public enum Spiciness { NOT,MILD,MEDIUM,HOT,FLAMING } Spiciness howHot = Spiciness.Hot;
在創建enum時,編譯器會自動添加一些有用的特性:
1.toString()方法2.ordinal()方法:用來顯示某個特定enum常量的聲明順序3.static values()方法:用來按照enum常量的聲明順序,產生由這些常量值構成的數組。enum有一個特別實用的特性,即它可以在switch語句內實用
Spiciness degree; switch(degree) { case NOT: break; case MILD: break; case MEDIUM: break; case HOT: break; case FLAMING: break; default: break; }