1. 程式人生 > >基礎 | Java的內部類

基礎 | Java的內部類

「內部類」 在面試時問的並不是很多,但是本人在面試Synopsys時就被問到過,建議還是要重點關注一下。

相信大家對於內部類都不陌生,但肯定也會感覺不太熟悉,因為在開發中的應用場景並不是很多,在此主要梳理一下 「談談對內部類的理解?在什麼場景中使用過內部類?」 相關問題。


談談對內部類的理解?

在Java中,可以將一個類定義在另一個類裡面或一個方法內,這樣的類即被稱為內部類,其框架體系如下:

下面分別對成員內部類、區域性內部類和匿名內部類的具體情況進行詳解分析。


談談對成員內部類的理解?

成員內部類是最普通的內部類,其定義位於另一個類的內部且在方法外,作為類及類的成員而存在:

  • 作為類,可宣告為abstract的,即可以被其他的內部類所繼承。
  • 作為類的成員,其可宣告為final、static(靜態內部類)和abstract的,且與外部類不同的是,內部類可以使用四種訪問修飾符進行修飾。

成員內部類如何訪問外部類?

答:成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員),使用「this.成員名」呼叫內部類的成員,使用「外部類名.this.成員名」呼叫外部類的成員。但需注意,靜態內部類只能訪問外部的靜態成員。

外部類如何訪問成員內部類?

答:必須先在外部類中建立一個成員內部類的物件,再通過指向該物件的引用來訪問內部類的成員。但對於靜態內部類和非靜態內部類而言,例項化內部類的方式不同:

// 設類ClassA有靜態內部類ClassB和普通內部類ClassC
ClassA classA = new ClassA();
ClassA.B classB = new ClassA.B();
ClassA.C classC = classA.new ClassC();

靜態內部類與非靜態內部類有什麼區別?

答:對於靜態內部類和非靜態內部類的詳細區別,建議好好閱讀下「關鍵字static」一文。


談談對區域性內部類的理解?

區域性內部類是定義在一個方法內或一個作用域(如if條件判斷程式碼塊)中的類,其和成員內部類的區別在於區域性內部類的訪問僅限於該方法內或該作用域中。

注意事項:

  • 區域性內部類可以訪問當前程式碼塊的常量以及其外部類的所有成員。
  • 區域性內部類非外部類的成員,故外部類無法訪問該內部類。
  • 區域性內部類可以看做一個區域性變數,不能有public、protected、private和static修飾。

談談對匿名內部類的理解?

匿名內部類指沒有名字的內部類,故其只能使用一次,通常用來簡化程式碼編寫,如Android中為控制元件新增監聽事件。

注意事項:

  • 匿名內部類必須繼承一個父類或實現一個介面,進而對繼承方法進行實現或重寫。
  • 匿名內部類是唯一一種沒有構造器的類,其在編譯時由系統自動起名為「外部類名$序號.class」,如「Outter$1.class」。
  • 匿名內部類一定是在new的後面,僅用於建立該匿名內部類的一個例項。

應用場景:最常用的情況就是在多執行緒的實現上,因為要實現多執行緒必須繼承Thread類或是繼承Runnable介面。


在什麼場景中使用過內部類?

這個問題不好回答,在此簡單總結下內部類的優勢,大家可以據此分析其實際應用場景。

  • 每個內部類都能獨立繼承一個父類或一個介面的實現,使得多繼承的解決方案更加完整。
  • 方便將存在一定邏輯關係的類組織在一起,又可以對外界進行隱藏(體現封裝性)。
  • 方便編寫事件監聽程式和多執行緒程式碼。

擴充套件面試題

問:成員內部類為什麼可以隨意訪問外部類的成員?

答:編譯器會預設為成員內部類添加了一個指向外部類物件的引用,故可在成員內部類中隨意訪問外部類的成員。(篇幅有限,不再過多贅述,有興趣可以反編譯Java程式碼檢視具體原理。)

問:區域性內部類和匿名內部類為何只能訪問區域性final常量?

答:如果區域性變數的值在編譯期間就可以確定,則直接在區域性內部類或匿名內部類內部建立一個拷貝。如果區域性變數的值無法在編譯期間確定,則通過構造器傳參的方式來對拷貝進行初始化賦值。限制其只能訪問final變數,主要是為了保證資料的一致性。(不太好理解,大家先做一個簡單瞭解,後續有機會再來單獨講講這個問題吧。)

思考:成員內部類、區域性內部類和匿名內部類經編譯後的位元組碼檔名稱分別是什麼?

留作思考吧。


推薦閱讀


歡迎關注

Java名企面試吧,每天10點24分,我們不見不散!

丙子先生的宗旨是,每天以短篇幅講高頻面試題,不增加太多負擔,但需要持之以恆。

能力有限,歡迎指教!