學習Java類必須知道的幾點
1、類的加載執行順序
看一下如下的例子:
運行結果如下:
可以看出類內的加載順序為:
(1)初始化變量。對于靜態變量肯定要首先進行初始化,因為后面的方法可能會使用這個變量,或者構造函數中也可能用到。而對于非靜態變量而言,由于匿名塊內、非靜態方法和構造函數都可以進行操作(不僅僅是初始化),所以要提前進行加載和賦默認值。
(2)初始化靜態代碼塊,多個靜態代碼塊按順序加載,這里需要注意:在這個順序不難是類內書寫的順序,也是類加載的順序,也就是說如果子類也有靜態代碼塊,則子類的也加載。由于靜態代碼塊可能會負責變量的初始化,或者是對象等的初始化,這樣在構造函數或者方法中就變得可用了。而順序加載多半是由于Java是按順序執行代碼的原因。
(3)匿名代碼塊,這個要后初始化于靜態代碼塊,因為其依然屬于實例對象,而不屬于類。在這里可以對非靜態成員變量進行初始化工作。
(4)構造函數 這里需要解釋一下,為什么初始化子類必先初始化父類,由于子類可能會繼承父類的屬性或方法,所以肯定要先初始化父類了,而初始化父類則必須要調用父類的構造函數。
至于方法不用考慮,因為方法不用初始化,所以無論是靜態還是不靜態,和這個沒有關系。
其實如上的代碼還能說明一些問題,可以看到,在父類中通過this.s()調用的是子類的方法,子類的s()方法覆蓋了父類的方法后,無論在哪里調用,都是調用子類的方法。
不可變類是指當創建了這個類的實例后,就不允許修改它的屬性值。在JDK的基本類庫中,所有基本類型的包裝類,如Integer、Long等都是不可變類,除此之外還有java.lang.String也是不可變類。不可變類的實例一但創建,其內在成員變量的值就不能被修改。創建一個不可變類需要如下條件:
1. 對于一般成員都是private,還可以使用public static final 來定義一個全局的常量。
2. 不提供對成員的修改方法,例如:setXXX()
3. 確保所有的方法不會被重載。手段有兩種:使用final Class(強不可變類),或者將所有的類方法加上final關鍵字(弱不可變類)。
4. 如果某一個類成員不是原始變量(primitive)或者不可變類,必須通過在成員初始化或者get方法時通過深度clone方法,來確保類的不可變。
其它的都好理解,下面來著重解釋一下第4條。舉個例子:
可以看到,不可變類中的數組內容發生了改變。究其原因就是 - 關鍵字final僅對其直接指向的對象有用,并且final引用可以指向帶有非final域的對象。
為了避免這個問題,必須對數組進行深度克隆。也就是專門再為不可變類中的數組開避一份內存空間,然后將參數的值賦值過去。正確的寫法如下:
不可變類有一些優點,比如因為它的對象是只讀的,所以多線程并發訪問也不會有任何問題。當然也有一些缺點,比如每個不同的狀態都要一個對象來代表,可能會造成性能上的問題。
內部類就是在一個類的內部定義的類,內部類中不能定義靜態成員(靜態成員不是對象的特性,只是為了找一個容身之處,所以需要放到一個類中而已,把“全局變量”放在內部類中就是毫無意義的事情,所以被禁止),內部類可以直接訪問外部類中的成員變量,即使這個成員變量是由private來修飾的。
同樣拿不可變類來舉一個例子。假如這個不可變類中有許多的private final屬性需要初始化,這時候看起來就不太方便。可能有人會采用工廠方法來解決,但有時候也可以使用靜態內部類來解決這一問題。如下:
來測試一下:
Update [author=Author [name=mazhi], updateText=abc, createTime=0]
在方法外部定義的內部類可以加上static關鍵字、可以定義成public、protected、默認的、private等多種類型,而普通類只能定義成public和默認的這兩種類型。在外面引用靜態內部類的名稱為"外部類名.內部類名"。不需要創建外部類的實例對象,就可以直接創建靜態內部類。例如:
Update.Builder b = new Update.Builder(); // 獲取靜態內部類的實例對象
由于不依賴于外部類的實例對象,所以能訪問外部類的非static成員變量。
想了解更多的內部類,可以查閱其它資料。
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!