你強任你強,我幹我本行——Java基礎(中)

午夜12點發表於2018-03-08

五、內部類

內部類:定義在一個類的中的類,雖然知道Java有這個特性,但是在實際工作中卻很少用到,只有在看原始碼時看到多處應用到內部類,以下參考了《Thinking in Java》和《java core》

5.1 為什麼要用內部類:

①因為java只能單繼承,運用內部類可以實現多重繼承,所以每個內部類都能獨立地繼承自一個(介面的)實現,所以無論外圍類是否已經繼承了某個(介面的)實現,對於內部類都沒有影響。
②內部類可以訪問外部類物件的所有成員。
③若類只需要例項化一次,可以使用匿名內部類。

5.2 為什麼內部類可以訪問外部類物件的所有成員

因為.
eg:
宣告一個擁有內部類的類:
因為編譯器修改了所有的內部類的構造器,新增了一個外部類引用的引數


    public class OuterClass{
        class InnerClass{}
    }
複製程式碼

javac編譯後會有2個檔案,因為每個類都會產生一個.class檔案,內部類的命名有嚴格的規則,外部類美元符號加上內部類,如下


class OuterClass$InnerClass {
    OuterClass$InnerClass(OuterClass var1) {
        this.this$0 = var1;
    }
    private void study() {
    }
}
複製程式碼

3.在方法和作用域內的內部類
①一個定義在方法中的類
②一個定義在作用域內的類,此作用域在方法的內部
③一個實現了介面的匿名類
④一個匿名類,他擴充套件了有非預設構造器的類
⑤一個匿名類,它執行欄位初始化
⑥一個匿名類,它通過例項初始化實現構造(匿名類沒有建構函式)
注:
內部類訪問區域性變數,區域性變數必須是常量(final修飾)
靜態巢狀類與內部類區別:
靜態巢狀類可以完全獨立於外圍類存在用來隱藏自己,而內部類是外圍類的一部分,內部類物件是以外部類物件存在為前提.

六、泛型

6.1 為什麼用泛型?

因為集合在新增時可以放object型別元素,也就是說任何object子類都能進入此集合無論在編譯器還是執行時都不會有問題,當我們獲取集合元素時取出來的是object引用,但遍歷時無法強轉多個特定型別,除非多個分支instance of判斷型別。所以決定使用泛型,用尖括號括起來型別引數,它指定了這個集合可以儲存的型別,可以在編譯期防止將錯誤型別的物件放入集合中.

6.2 泛型定義

①定義類

你強任你強,我幹我本行——Java基礎(中)
②定義方法

你強任你強,我幹我本行——Java基礎(中)

6.3 泛型擦除

虛擬機器沒有泛型型別物件,所有物件都屬於普通類,無論何時定義一個泛型型別,都自動提供了一個相應的原始型別,原始型別的名字就是刪去型別引數後的泛型型別名,擦除型別變數將擦除到它的第一個邊界,並替換為限定型別(無限定型別用Object),<>不能用基本資料型別,要用引用型別因為泛型擦除。只能有Object型別(引用型別).
T → Object
T extends Comparable& Serializable → Comparable
4.既然泛型擦除,為什麼還會返回特定型別?
因為編譯器會把返回的Object型別自動強轉為特定型別。也因為泛型擦除,會出現以下問題:

你強任你強,我幹我本行——Java基礎(中)
由於執行時泛型擦除,這時子類有2個方法一個是繼承自父類的形參為Object型別的study方法,另一個自己重寫的引數為String型別study方法,那麼當我們向上轉型形成多型呼叫study方法,這顯然是不同的方法它是如呼叫到後者的?
javac編譯,javap -c反彙編一哈,我們可以看到下圖
你強任你強,我幹我本行——Java基礎(中)
父類引用genic,只有父類一個Object型別引數方法,由於Genic是GenicChild型別的會呼叫其Object型別引數方法,此方法為橋方法,它再呼叫String型別方法坐做了一個轉換


    public void study(Object obj){
        study((String)obj);
    }
複製程式碼

當我們定義一個返回型別是泛型的方法,子類重寫其父類方法,那麼子類有2個方法一個泛型擦除的Object返回型別方法,一個是特定型別方法。這兩個方法的方法簽名一樣,我們知道一個類不能擁有2個方法簽名相同的方法,這樣是不合法的,但是在虛擬機器中返回型別可以用來區分方法,虛擬機器能夠正確處理這一情況
注:
①過載沒有橋方法,重寫父類方法泛型定義成擦除後的型別也不會有橋方法
②陣列不能用泛型,可以用資料結構是陣列的集合arraylist
③泛型不能例項化.eg new T(),new T[]因為泛型擦除不知道具體哪個型別

6.4 萬用字元

T 自定義泛型型別
? 預設是Object及其子類,也就是java的所有物件
? extends T 接受T型別或者T的子型別物件
? super T 接受T型別或者T的父型別物件

七、異常

7.1 異常體系:

你強任你強,我幹我本行——Java基礎(中)
Throwable是java異常的超類,他有兩個子類,Error和Exception,Error指系統錯誤例如OOM由虛擬機器管理,而另一個Exception在Java類庫、使用者方法以及執行時故障中都可能丟擲的異常。Exception又分為checked Exception和unchecked Exception這2種,前者是受檢查異常例如讀檔案時的FileNotFoundException,後者非受檢查異常也叫執行時異常都繼承RuntimeExcetion自動被虛擬機器丟擲例如大名鼎鼎的NullPointerException.

7.2 丟擲異常

throw 異常生成階段:手動丟擲異常物件
throws 宣告方法可能要丟擲的各種異常類
丟擲的異常可以catch捕獲,也可以繼續拋到上層,注意重寫限定,若父類方法沒有丟擲異常,子類重寫的方法只能捕獲異常無法向上拋,並且catch異常最詳細的最先寫越泛的後寫。在專案裡一般都會有自定義異常,並且針對不同的錯誤場景會有不同的錯誤碼,在整個專案中不同部門負責的系統定義的錯誤碼都會有所不同這樣我們在排查時直接根據錯誤碼就能較快地發現哪個環節出了問題。
注:

7.3.finally

因為finally裡的程式碼總會執行,所以一般用來關閉資源物件(在JDK7及以上若實現了java.lang.AutoCloseable介面的物件,和實現了java.io.Closeable介面的物件可以用try—with—resources),最好不要在finally裡用return。

相關文章