Thinking In Java Part03(對象)

1、存儲位置	
	1.1、寄存器:最快的存儲區,因爲它位於不同於其他存儲區的地方——處理器內部,但是寄存器的數量極其有限,所以寄存器根據需求進行分配。你不能直接控制,也不能在程序中感覺到寄存器存在的任何跡象(另一方面,C和C++允許向編譯器建議寄存器的分配方式)
	1.2、堆棧。位於通用RAM(隨機訪問存儲器)中,但通過堆棧指針可以從處理器那裏獲得直接支持。堆棧指針若向下移動,則分配新的內存;若向上移動,則釋放那些內存。這是一種快速有效的分配存儲方法,僅次於寄存器。創建程序時,Java系統必須知道存儲在堆棧內所有項的確切生命週期 ,以便上下移動堆棧指針。這一約束了程序的靈活性,所以雖然某些Java數據存儲於堆棧中——特別是對象引用,但是Java對象並不存儲於其中。
	1.3、堆:一種通用的內存池(也位於RAM區),用於存放所有的Java對象。堆不同於堆棧的好處是:編譯器不需要知道存儲的數據在堆裏存活多長時間。因此,在 堆裏分配存儲有很大的靈活性。當需要一個對象時,只需用new寫一行簡單的代碼,當執行這行代碼時,會自動在堆裏進行存儲分配。當然,爲這種靈活性必須要付出對應的代價:用堆進行存儲分配和清理可能比用堆棧進行存儲分配需要更多的時間。
	1.4、常量存儲。常量值通常直接存放在程序代碼的內部,這樣做安全,因爲它們永遠不會被改變。有時,在嵌入式系統中,常量本身會和其他部分隔離開,所以在這種情況下,可以選擇將其存放在ROM(只讀存儲器)中【這種存儲區的一個例子是字符串池,所有字面常量字符串和具有字符串值的常量表達式都自動是內存限定的,並且會置於特殊的靜態存儲區中】。
	1.5、非RAM存儲。如果數據完全存活於程序之外,那麼它可以不受程序的任何控制,在程序沒有運行時也可以存在。2個基本的例子爲流對象和持久化對象。在流對象中,對象轉化成字節流,通常被髮送給另一臺及其。在“持久化對象”中,對象被存放於磁盤上,因此,即使程序終止,它們仍可以保持自己的狀態。這種存儲方式的技巧在於:把對象轉化成可以存放在其他媒介上的事物,在需要時,可恢復成常規的、基於RAM的對象。Java提供了毒地輕量級持久化的支持,而諸如JDBC和Hibernate這樣的機制提供了更加複雜的對在數據庫中存儲和讀取對象信息的支持。
2、返回類型描述的是 在調用方法之後從方能發返回的值。參數列表給出了要傳給方法的信息的類型和名稱。方法名和參數列表(他們合起來被稱爲“方法簽名”)唯一地標識出某個方法
3、static關鍵字
	當創建類時,就是在描述那個類的對象的外觀與行爲。除非用new創建那個類的對象,否則,實際上並未獲得任何對象。執行new來創建對象時,數據存儲空間才被分配,其方法才供外界調用。
	現在有2種情況上述方法無法結局。一:只想爲某特定域分配單一存儲空間,而不去考慮究竟要創建多少對象,甚至根本就不創建任何對象。二:希望某個方法不與報案後它的類的任何對象關聯在一起。也就是說,即使沒有創建對象,也能夠調用這個方法。
	通過static關鍵字可以滿足。當聲明一個事物是static時,就意味着這個域或方法不會與包含它的那個類的任何對象實例關聯在一起。所以,即使從未創建某個類的任何對象,也可以調用其static方法或訪問其static域。通常,你必須創建一個對象,並用它來訪問數據或方法。因爲非static域和方法必須知道它們一起運作的特定對象。	
	static方法的一個重要用法就是在不創建 任何對象的前提下就可以調用它										
4、Java沒有sizeof
	在C和C++中,sizeof 可以告訴你爲 數據項分配的字節數。在C和C++中,需要使用sizeof最大原因是爲了移植。不同的數據類型在不同的機器上可能有不同的大小,所以在進行一些與存儲空間有關的運算時,程序員必須獲悉那些類型具體有多大。例如,一臺計算機可用32位來保存整數,而另一臺只用16位保存。Java不需要sizeof操作符來滿足這方面的需要,因爲所有數據類型在所有機器中的大小都是相同的。
5、初始化和清理是涉及安全的兩個問題。許多C程序的錯誤都源於程序員忘記初始化變量。特別是在使用程序庫時,如果用戶不知道如何初始化庫的構件(或者是用戶必須進行初始化的其他東西)。清理也是一個特殊的問題,當使用完一個元素時,它對你也就不會有什麼影響了,所以很容易忘記,這樣這個元素佔用的資源就會一直得不到釋放,結果是資源用盡。
	C++引入了構造器的概念,這是一個在創建對象時被自動調用的特殊方法,Java也採用了構造器,並額外提供了垃圾回收器。
5、爲了讓方法名相同而形式參數不同的構造器同時存在,必須用到方法重載
6、垃圾回收器如何工作
	“停止-複製”和“標記-清掃”工作都必須在程序暫停的情況下才能進行。垃圾回收期會定期進行完整的清理動作——大型對象仍然不會被複制 (只是其代數會增加),內含小型對象的那些塊則被複制 並整理。Java虛擬機會進行監視,如果所有對象都很穩定,垃圾回收器的效率降低的話,就切換到“標記-清掃”方式,同樣,Java迅疾會跟蹤“標記-清掃”的效果,鑰匙堆空間出現很多碎片,就會切換回“停止-複製”方式。這就是“自適應”技術,也可以稱之爲“自適應的、分代的、停止-複製、標記-清掃”式垃圾回收器。
	Java虛擬機中有許多附加技術用以提升速度。尤其是與加載器操作相關的,被稱爲“即時”(Just-In-Time,JIT)編譯器技術。這種技術可以把程序全部或部分編譯成本地機器碼(這本來是Java虛擬機的而工作),程序運行速度因此得以提升。當需要裝載某個類(通常是在爲 該類創建第一個對象)時,編譯器會先找到其.class文件,然後將該類的字節碼裝入內存。此時,有兩種方案可供選擇。一種就讓即時編譯器編譯代碼。但這種做法有兩種缺陷:這種加載動作散落在整個程序生命週期內,累加起來要花更多時間;並且會增加可執行代碼的長度(字節碼要比即時編譯器展開後的本地機器名小很多),這將導致頁面調度,從而降低程序速度。 另一種做法稱爲 惰性評估(lazy evaluation),意思是即時編譯器只在必要的時候才編譯代碼。這樣,從不會被執行的代碼也許就壓根不會被JIT所編譯。新版JDk中的Java HotSpot技術就用了類似方法,代碼每次被執行都會做一些優化,所以執行的次數越多,它的速度越快。
7、靜態數據初始化
	初始化的順序是先靜態對象(如果它們尚未因前面的對象創建過程而被初始化),而後是“非靜態”對象。從輸出結果中可以觀察到這一點。要執行main()(靜態方法),必須加載StaticInitialization類,然後其靜態域被初始化,這將導致它們對應的類也被加載,並且由於它們也都包含靜態的對象X,因此X隨後也被加載。這樣,在這個特殊的程序中的所有類在main()開始之前就都被加載了。
	對象的創建過程,假設有個名爲Cat的類:
		7.1、即使沒有顯式地使用static關鍵字,構造器實際上也是靜態方法。隱藏,當首次創建類型爲Cat的對象時(構造器可以看成靜態方法),或者Cat類的靜態方法/靜態域首次被訪問時,Java解釋器必須查找類路徑,以定位Cat.class文件。
		7.2、然後載入Cat.class(這就創建一個Class對象),有關靜態初始化的所有動作都會被執行。隱藏,靜態初始化只在Class對象首次加載的時候進行一次。
		7.3、當用new Cat()創建對象的時候,首先將在堆上爲Cat對象分配足夠的存儲空間。
		7.4、這塊存儲空間會被清零,這就自動地將Cat對象中的所有基本類型數據都設置爲默認值(對數字來說是0,對布爾型和字符型也相同),而引用則被設置成了null。
		7.5、執行所有出現於字段定義處的初始化動作。
		7.6、執行構造器。這可能會牽涉到很多動作,尤其是涉及到繼承的時候。
8、庫單元
	當編寫一個Java源文件時,此文件通常被稱爲編譯黨員(有時候被稱爲轉譯單元)。每個編譯單元都必須有一個後綴名.jva,而在編譯單元內則可以有一個public類,該類的每次必須與文件的名稱相同(包括大小寫,但不包括文件的後綴名.java)。每個編譯單元只能有一個public類,否則編譯器就不會接受。如果在該編譯單元之中還有額外的類的話,那麼在包之外的世界是無法看到這些類的,這是因爲它們不是public類,而且它們主要用來爲主public類提供支持。
9、代碼組織
	當編譯一個.java文件時,在.java文件中的每個類都會有一個輸出文件,而該輸出文件的名稱與.java文件中每個類的名稱相同,只是多了一個後綴名.class。因此,在編譯少量.java文件之後,會得到大量的.class文件。如果用編譯型語言編寫過程序,那麼對於編譯器產生一箇中間文件(通常是一個obj文件),然後再與通過鏈接器(用以創建一個可執行文件)或類庫產生器(librarian,用以創建一個類庫)產生的其他同類文件捆綁在一起的情況。但這並不是Java的工作方式。Java可運行程序是一組可以打包並壓縮爲一個Java文檔文件(JAR,使用Java的的jar文檔生成器)的.class文件。Java解釋器負責這些文件的查找、裝載和解釋。
	類庫實際上是一組類文件。其中每個文件都有一個public類,以及任意數量的非public類。因此每個文件都有一個構件。如果希望這些構件(每一個都有它們自己的獨立的.java和.class文件)從屬於同一個羣組,就可以使用關鍵字package。
	pacakge和import關鍵字允許你做的,是將單一的全局名字空間分隔開,使得無論多少人使用Internet以及Javav開始編寫類,都不會出現名稱衝突問題。
10、創建獨一無二的包名【Java解釋器的運行過程】
	Java解釋器的運行過程如下:首先,找出環境變量CLASSPATH(可以通過操作系統來設置,有時也可通過安裝程序-用來在你的機器上安裝Java或基於Java的工具來設置)。CLASSPATH包含一個或多個目錄,用來查找.class文件的根目錄。從根目錄開始,解釋器獲取包的名稱並將每個句點並將每個句號替換成反斜槓,以從CLASSPATH根中產生一個路徑名稱(於是package com.xxx.zhang就變成了com\xxx\zhang或com/xxx/zhang或其他,這一切取決於操作系統)。得到的路徑會與CLASSPATH的各個不同的項相連接,解釋器就在這些目錄中查找與你所要創建的類名稱相關的.class文件(解釋器還會去查找某些設計Java解釋器所在位置的標準目錄)。
11、接口和實現
	訪問權限的控制常被稱爲是具體實現的隱藏。把數據和方法包裝進類中,以及具體實現的隱藏,常共同被稱作是封裝。其結果是一個同時帶有特徵和行爲的數據類型。
	出於2個很重要的原因,訪問權限控制將權限的邊界劃在了數據類型的內部。第一個原因是要設定客戶端程序員可以使用和不可以使用的界限。可以在結構中建立自己的內部機制,而不必擔心客戶端程序員會偶然地將內部機制當作是他們可以使用的接口的一部分。
	這個原因直接引出了第二個原因,即將接口和具體實現進行分離。如果結構是用於一組程序之中,而客戶端程序員除了可以向接口發送信息之外什麼也不可以做的話,那麼就可以隨意更改所有不是public的東西(例如有包訪問權限、protected和private的成員),而不會破壞客戶端代碼。
12、初始化位置
	12.1、在定義對象的地方,這意味着它們總是能在構造器被調用之前被初始化
	12.2、在類的構造器中
	12.3、就在正要使用這些對象之前,這種方式被稱爲惰性初始化。在生成對象不值得即不必每次都生成對象的情況下,這種方式可以減少額外的負擔。
	12.4、使用實例初始化。
13、protected關鍵字
	爲了隱藏某些事物,但仍然允許導出類的成員訪問他們。protected是爲了指明“就類用戶而言,這是private的,但對於任何繼承與此類的導出類或其他任何位於同一個包內的類來說,他卻是可以訪問的”(protected也提供了包內訪問權限)
	儘管可以創建protected域,但最好的方式還是將域保持爲private,應當一直保留“更改底層實現”的權利,然後通過protected方法來控制類的繼承者的訪問權限。	
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章