標籤:
1——物件導向和JVM基礎
1.java中的4種訪問制許可權:
(1).public:最大存取控制許可權,對所有的類都可見。
(2).protect:同一包可見,不在同一個包的所有子類也可見。
(3).default:包存取權限,即同一個包中的類可以可見。預設不顯式指定存取控制許可權時就是default包存取控制許可權。
(4).private:最嚴格俄存取控制許可權,僅該類本身可見,對外一切類都不可以訪問(反射機制可以訪問)。
2.物件導向編程中兩種對象組合方式——is-a 和 has-a:
(1).is-a組合:一個類繼承具有相似功能的另一個類,根據需要在所繼承的類基礎上進行擴充。
優點:具有共同屬性和方法的類可以將共用資訊抽象到父類中,增強代碼複用性,同時也是多態的基礎。
缺點:子類中擴充的部分對父類不可見,另外如果共性比較少的時候使用繼承會增加冗餘代碼。
(2).has-a組合:has-a組合是在一個類中引用另一個類作為其成員變數。 優點:可擴充性和靈活性高。在對象組合關係中應優先考慮has-a組合關係。 缺點:具有共性的類之間看不到派生關係。
3.多態:
在物件導向編程中,子類中擁有和父類相同方法簽名的方法稱為子類方法覆蓋父類方法,當調用子類方法的某個操作時,不必明確知道子類的具體類型,只需要將子類類型看作是父類的引用調用其操作方法,在運行時,JVM會根據引用對象的具體子類類型而調用應該的方法,這就是多態。
多態的基礎是java物件導向編程的晚綁定機制。編程中有如下兩種綁定機制:
(1).早綁定:一般在非物件導向程式設計語言中使用,在程式編譯時間即計算出具體調用方法體的記憶體位址。
(2).晚綁定:物件導向程式設計語言中經常使用,在程式編譯時間無法計算出具體調用方法體的記憶體位址,只進行方法參數類型和傳回值類型的校正,在運行時才能確定具體要調用方法體的記憶體位址。
4.java單繼承的優點:
相比於C++的多繼承,java只支援類的單繼承,java中的所有類的共同基類是Object類,Object類java類樹的唯一根節點,這種單繼承有以下好處:
(1).單繼承可以確保所有的對象擁有某種共同的特性,這樣對於JVM虛擬機器對所有的類進行系統級的操作將提供方便,所有的java對象可以方便地在記憶體堆棧中建立,傳遞參數也變的更加方便簡單。
(2).java的單繼承使得實現記憶體回收行程功能更加容易,因為可以確保JVM知道所有對象的類型資訊。
5.選擇容器物件兩個原則:
(1).容器所能提供不同的類型的介面和外部行為是否能夠滿足需求。
(2).不同容器針對不同的操作效率不同。
6.類型轉換:
Java中有兩種常見的類型轉換:向上類型轉換(upcast)和向下類型轉換(downcast):
(1).向上類型轉換(upcast):
向上類型轉換是將子類對象強制類型轉換為父類類型,經典用法是物件導向的多態特性。向上類型轉換時,子類對象的特性將不可見,只有子類從父類繼承的特性仍然保持可見,向上類型轉換時編譯器會自動檢查是否類型相容,通常是安全的。
(2).向下類型轉換:
向下類型轉換是將父類類型強制轉換為子類類型,轉換過後父類中不可見的子類特性又恢複可見度,向下類型轉換時,編譯器無法自動檢測是否類型相容,往往會產生類型轉換錯誤的運行時異常,通常不安全。
7.java中5個存放資料的地方:
(1).寄存器(Registers):位於CPU內部,是速度最快的儲存區,但是數量和容量有限。在java中不能直接操作寄存器。
(2).棧(Stack):棧位於通用隨機訪問儲存空間 (General random-access memory,RAM,記憶體) 中,通過處理器的棧指標訪問,棧指標從棧頂向棧底分配記憶體,從棧底向棧頂釋放記憶體。棧是僅次於寄存器的速度第二快的儲存空間,在java程式中,一般的8種 基本類型資料和對象的引用通常存放在棧記憶體中,不通過new關鍵字的字串對象也是存放在棧的字串池中。棧的優勢是,存取速度比堆要快,僅次於寄存器, 棧資料可以共用。但缺點是,存在棧中的資料大小與生存期必須是確定的,缺乏靈活性。
(3).堆(Heap):也是位於通用隨機訪問儲存空間 (General random-access memory,RAM,記憶體) 中的共用記憶體池。Java的堆是一個運行時資料區,類的對象從中分配空間,凡是通過new關鍵字建立的對象都存放在堆記憶體中,它們不需要程式碼來顯式的 釋放。堆是由記憶體回收來負責的,堆的優勢是可以動態地分配記憶體大小,生存期也不必事先告訴編譯器,因為它是在運行時動態分配記憶體的,Java的垃圾收集器 會自動收走這些不再使用的資料。但缺點是,由於要在運行時動態分配記憶體,存取速度較慢。
(4).常量儲存空間(Constant storage):java中的常量是存放在系統內嵌的唯讀記憶體中(read-only memory,ROM)的。
(5).非隨機儲存空間(Non-RAM storage):對於流對象和持久化對象,通常存放在程式外的儲存空間,如硬碟。
8.javadoc只處理public和protected存取控制許可權的文檔注釋,private和default許可權的穩定注釋將被忽略。
9.java中賦值運算:
基本類型賦值是直接複製值,賦值操作後,相互不影響。
參考型別賦值是複製引用值,相當於給對象取一個別名,賦值之後兩個引用指向同一個引用對象,相互之間有影響。
在Java中,向方法傳遞參考型別參數會改變參數的值,不讓參數受到影響的解決方案:在方法內首先先將引用複製一份,然後操作複製的對象。
10.移位元運算:
左移運算子<<:將位元位左移指定位元,右邊部分補0,左移一位相當於乘2。
右移運算子>>:將位元位右移指定位元,如果是正數,左邊第一位(符號位)補0,其餘位補0,如果是負數,左邊第一位補1,其餘位補0。右移一位相當於除2。
無符號右移運算子>>>:將位元位右移指定位元,不論是正數或者負數,左邊移除位統統補0。
11.java中,比int類型小的原始類型(char、byte、short)進行數學運算或者位元運算時,資料類型首先轉換成int類型,然後進行相應的運算。
12.方法重載(overloading):方法同名,參數列表不同稱為方法重載,注意方法的傳回值類型不同不能作為方法重載。
13.java中的解構函式:
Java中沒有像C/C++的解構函式,用來銷毀不用的對象是否記憶體空間,只有以下三個方法用於通知記憶體回收行程回收對象。
(1).finalize( )只是通知JVM的垃圾收集器當前的對象不再使用可以被回收了,但是記憶體回收行程根據記憶體使用量狀況來決定是否回收。
finalize()最有用的地方是在JNI調用本地方法時(C/C++方法),調用本地方法的解構函式消耗對象釋放函數。
(2). System.gc()是強制析構,顯式通知記憶體回收行程釋放記憶體,但是記憶體回收行程也不一定會立即執行,記憶體回收行程根據當前記憶體使用量狀況和對象的生命週期自行決定是否回收。
(3).RunTime.getRunTime().gc()和System.gc()類似。
注意:這三個函數都不能保證記憶體回收行程立即執行,推薦不要頻繁使用。
14.記憶體回收行程原理:
(1).引用計數(ReferenceCounting)記憶體回收演算法:
一種簡單但是速度較慢的記憶體回收演算法,每個對象擁有一個引用計數器
(Reference Counter),當每次引用附加到這個對象時,對象的引用計數器加1。當每次引用超出作用範圍或者被設定為null時,對象的引用計數器減1。記憶體回收 器遍曆整個對象列表,當發現一個對象的引用計數器為0時,將該對象移出記憶體釋放。
引用計數演算法的缺點是,當對象環狀相互引用時,對象的引用計數器總不為0,要想回收這些對象需要額外的處理。
引用計數演算法只是用來解釋記憶體回收行程的工作原理,沒有JVM使用它實現記憶體回收行程。
引用計數的改進演算法:
任何存活的對象必須被在靜態儲存區或者棧(Stack)中的引用所引用,因此當遍曆全部靜態儲存區或棧中的引用時,即可以確定所有存活的對象。每當 遍曆一個引用時,檢查該引用所指向的對象,同時檢查該對象上的所有引用,沒有引用指向的對象和相互自引用的對象將被記憶體回收行程回收。
(2).暫停複製(stop-and-copy)演算法:
記憶體回收行程的收集機制基於:任何一個存活的對象必須要被一個儲存在棧或者靜態儲存區的引用所引用。
暫停複製的演算法是:程式在運行過程中首先暫停執行,把每個存活的對象從一個堆複製到另一個堆中,已經不再被使用的對象被回收而不再複製。 暫停複製演算法有兩個問題:
a.必須要同時維護分離的兩個堆,需要程式運行所需兩倍的記憶體空間。JVM的解決辦法是在記憶體塊中分配堆空間,複製時簡單地從一個記憶體塊複製到另一個記憶體塊。
b.第二個問題是複製過程的本身處理,當程式運行穩定以後,只會產生很少的垃圾對象需要回收,如果記憶體回收行程還是頻繁地複製存活對象是非常低效能的。
JVM的解決方案是使用一種新的記憶體回收演算法——標記清除(mark-and-sweep)。 一般來說標記清除演算法在正常的使用情境中速度比較慢,但是當程式只產生很少的垃圾對象需要回收時,該演算法就非常的高效。
(3).標記清除(mark-and-sweep)演算法:
和暫停複製的邏輯類似,標記清除演算法從棧和靜態儲存區開始追蹤所有引用尋找存活的對象,當每次找到一個存活的對象時,對象被設定一個標記並且不被回收,當標記過程完成後,清除不用的死對象,釋放記憶體空間。
標記清除演算法不需要複製對象,所有的標記和清除工作在一個記憶體堆中完成。
注意:SUN的文檔中說JVM的記憶體回收行程是一個後台啟動並執行低優先順序進程,但是在早期版本的JVM中並不是這樣實現的,當記憶體不夠用時,記憶體回收行程先暫停程式運行,然後進行記憶體回收。
《Java編程思想》學習筆記(一)