當前位置:
首頁 > 知識 > 全面掌握Java內部類

全面掌握Java內部類

一直以來以為自己對 Java 基礎甚是清楚,然而面試時卻連內部類和靜態內部類的區別都無法回答圓滿,so~重新學習一遍,徹底掌握內部類。

內部類是一種非常有用的特性,它可以把一些邏輯相關的類組織在一起,並控制位於內部的類的可視性,下文中內部類均指非靜態內部類。

內部類的學習分為以下10個知識點:

1.創建內部類與連接外部類

2.內部類與向上轉型

3.局部內部類

4.匿名內部類

5.局部內部類和匿名內部類

6.嵌套類

7.內部類的繼承

8.內部類可以被覆蓋嗎

9.為什麼需要內部類

10.內部類標識符


1、創建內部類與連接外部類

全面掌握Java內部類

要想創建內部類的對象,必須使用外部類的對象,如上,且必須地具體指明這個對象的類型:OuterClassName.InnerClassName,然後通過 OuterClassInstance.new InnerClassName() 來創建內部類對象。

內部類對象會暗暗連接到創建它的外部類對象上,捕獲外部類的對象引用,然後在內部類中訪問此外部類的成員時,就是通過這個引用來訪問的,並且擁有其外部類的所有元素的訪問權。正是由於此原因,Android 中非靜態內部類創建靜態實例才會造成內存泄漏。

在內部類中通過 OuterClassName.this 可獲取外部類對象,如上代碼中通過 Car.this 獲取 Car 類對象。


2、內部類與向上轉型

當將內部類向上轉型為基類,尤其是轉型為一個介面的時候,此內部類能夠隱藏這個介面的實現,如下例:

全面掌握Java內部類

全面掌握Java內部類


3、局部內部類

前面提到的都是處於外部類中的內部類,而內部類也可以定義在一個方法裡面或者在任意的作用域中,這麼做有以下兩個理由:

1.如實現某介面的內部類,可以在方法中創建並返回對其的引用

2.要解決一個複雜的問題,需要創建一個類來輔助,但不希望這個類是公共可用的

例1:在方法中定義內部類:

全面掌握Java內部類

例2:在任意作用域中定義內部類:

全面掌握Java內部類

定義在一個方法裡面或者在任意的作用域中的內部類也叫作局部內部類,局部內部類不能有 private 等訪問說明符,因為它不是外部類的一部分,但是它可以訪問當前代碼塊內的常量以及外部類中的所有成員:

全面掌握Java內部類

書中說可以訪問當前代碼塊內的常量,這裡有點不解,coupon2 是常量?


4、匿名內部類

上例中 getTyre() 方法要創建一個 cost 對象,從 cost tyre = car.getTyre(); 看出我們並不關心內部類的名字 Tyre,只要返回的是 cost 類對象就足夠了,所以這裡可以用匿名內部類來實現,顧名思義,它沒有名字,如下例:

全面掌握Java內部類

你可能會有疑問,這段代碼可以編譯通過嗎?應該是 getTyre(final double p) 吧?確實,在匿名內部類中使用一個在其外部定義的對象,那麼編譯器必須要求其參數引用是 final 類型,以上代碼在低於 Java 8 的版本編譯不會通過,但是在 Java 8 版本不用 final 修飾局部變數也可以編譯通過,只不過不能修改值,只能列印輸出或賦值給其他變數。


5、局部內部類和匿名內部類

首先來看局部內部類和匿名內部類的對比實現:

全面掌握Java內部類

getTyre() 方法用來創建一個 cost 類對象,我們分別使用局部內部類和匿名內部類實現了這個功能,它們具有相同的行為和能力,既然局部內部類的名字在方法外是不可見的,那為什麼我們仍然使用局部內部類而不是匿名內部類呢?唯一的理由是:我們需要一個已命名的構造器,或者需要重載狗仔器,而匿名內部類只能用於實例初始化,所以使用局部內部類而不使用匿名內部類的另一個理由就是:需要不止一個該內部類的對象。


6、嵌套類

如果不需要內部類對象與其外部類對象之間有聯繫,那麼可以將內部類聲明為 static,即靜態內部類,也稱嵌套類,靜態內部類和非靜態內部類的最大區別就是非靜態內部類對象隱士的保存了一個外部類對象的引用,這意味著:

1.不需要外部類的對象就可以創建靜態內部類的對象

2.不能從靜態內部類的對象中訪問非靜態的外部類對象

3.靜態內部類中可以定義靜態或者非靜態的成員,而非靜態內部類則不能有靜態成員。

全面掌握Java內部類

這也是靜態內部類和內部類的關鍵區別。此外靜態內部類也可定義在介面內部:

全面掌握Java內部類

如果你想要創建某些公共代碼,使得它們可以被某個介面的所有不同實現所公用,那麼使用介面內部嵌套類會顯得很方便。


7、內部類的繼承

怎麼繼承自一個內部類?內部類的構造必須依賴其外部類對象,所以在繼承內部類的時候,事情會變得複雜,比如我們要繼承自 Size 類:

全面掌握Java內部類

可以這樣寫:

全面掌握Java內部類

編譯器會報錯: No enclosing instance of type 『com.example.Tyre』 is in scope ,即缺少 Tyre 類的實例,若要創建位於 Tyre 內部的 Size 類,則必須要有 Tyre 的實例對象,要解決這個問題,需要引入 Tyre 實例且說清它們之間的關聯:

全面掌握Java內部類

編譯通過。


8、內部類可以被覆蓋嗎

如果創建了一個內部類,然後繼承其外部類並重新定義此內部類時,內部類可以被覆蓋嗎?例如:

全面掌握Java內部類

在 Car 的構造器中新建的 Tyre 是 Car 中的 Tyre 還是 BigCar 中的 Tyre 呢?運行程序輸出:

new Car()

new Tyre()

BigCar 中定義的 Tyre 內部類並沒有覆蓋 Car 中的 Tyre 內部類,實際上這兩個內部類是完全獨立的兩個實體,各自在自己的命名空間內,沒有誰覆蓋誰之說。

9、為什麼需要內部類

也就是說,內部類存在的意義是什麼呢?為什麼 Sun 公司如此費心地增加這項語言特性呢?這裡將內部類的意義總結為以下四點:

A. 邏輯上被包含且對外隱藏

如果一個類在邏輯上被包含於另一個類,那麼將此類設置為另一個類的內部類,比如輪胎類可以寫作汽車類的內部類:

全面掌握Java內部類

上面代碼中只存在被包含關係,也可通過組合方式實現,寫作內部類是沒有必要的,當想對外保密汽車使用何種輪胎時,寫作內部類才是有必要的:

全面掌握Java內部類

B. 實現多重繼承

每個內部類都能獨立的繼承一個介面,無論外部類是否已經繼承了某個介面的實現,對於內部類都沒有影響。內部類提供可以繼承多個抽象類或具體的類的能力,有效的實現了多重繼承,網上一個實例簡單直觀的展示了通過內部類實現多重繼承(兒子利用多重繼承來繼承父親和母親的優良基因):

全面掌握Java內部類

全面掌握Java內部類

C. 閉包與回調

閉包是一個可調用的對象,它記錄了一些信息,這些信息來自於創建它的作用域。通過這個定義,可以看出內部類是面向對象的閉包,因為它不僅包含外部類對象(創建內部類的作用域)的信息,還自動擁有一個指向此外部類對象的引用,在此作用域內,內部類有權操作所有的成員,包括private成員。

通過內部類提供閉包功能比指針更靈活、更安全

例如:一個介面程序員和一個基類作家都有一個相同的方法work,相同的方法名,但是其含義完全不同,這時候就需要閉包。

全面掌握Java內部類

閉包實現代碼如下:

全面掌握Java內部類

WriterProgrammer 繼承自 Writer , 直接實現父類作家的work()方法,然後使用內部類實現程序員的work()方法回調code()方法。如果WriterProgrammer 同時繼承自 Writer 且實現 programmer 介面,那麼就不能同時實現作家和程序員的意義不同的 work()方法:

全面掌握Java內部類

D. 控制框架

應用程序框架就是被設計用以解決某類特定問題的一個類或一組類,而控制框架就是一類特殊的應用程序框架,它用來解決響應事件的需求,主要用來響應事件的系統被稱作事件驅動系統。 Java Swing 庫就是一個控制框架,它優雅的解決了 GUI 的問題,並使用了大量的內部類

控制框架的完整實現是由單個類創建的,內部類用來表示解決問題所必須的各種不同的 action,另外內部類能夠很容易的訪問外部類的任意成員,可以讓這種實現更輕鬆。

例如控制溫室的運作:控制燈光、水、溫度調節器的開關等,每個行為都是完全不同的,使用內部類可以在單一的類中產生對同一個基類 Event 的多種導出版本,對於溫室系統的每一種行為,都繼承一個新的 Event 內部類,並在要實現的 action() 中編寫控制代碼:

全面掌握Java內部類


10、內部類標識符

每個類都會產生一個.class文件,其中包含了如何創建該類型的對象的全部信息,內部類也必須生成一個 .class 文件,從而可以包含它自己的 Class 對象信息,這些類文件的命名有嚴格的規則:外部類名字+「$」+ 內部類名字,例如:

全面掌握Java內部類

生成的 .class 文件包括:

Car.class

Car$Tyre.class

如果內部類是匿名的,編譯器會簡單的產生一個數字作為其標識符,如果內部類是嵌套在別的內部類之中,只需直接將它們的名字加在其外部類標識符與」$」後面,這是 Java 的標準命名方式,產生的文件自動都是平台無關的。


總結

本文主要參考 Java 編程思想書中對內部類部分的講解思路,將各部分知識點轉換為自以為更易理解的例子~嗯~總算較為全面的理解內部類了~以後應該不會怕啦hhh~


學習Java的同學注意了!!!

學習過程中遇到什麼問題或者想獲取學習資源的話,歡迎加入Java學習交流群495273252,我們一起學Java!

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Java團長 的精彩文章:

程序員的未來在哪裡?
Java並發全景圖(1.1版本)
Java多線程詳解——生產者和消費者
SSH框架的整合詳解

TAG:Java團長 |

您可能感興趣

荷蘭情報部門聲稱掌握俄黑客組織介入美國總統大選的重要證據;因 CPU 漏洞 Canonical 宣布推遲發布 Ubu
Galaxy S9 Plus相機指南:掌握這些技巧和竅門
影音娛樂一手掌握西數My Passport SSD體驗
這裡是YouTube總部槍擊案目前所掌握的信息
Android 開發應該掌握的 Proguard 技巧
一文掌握InfiniBand技術和架構
別具風格的機甲遊戲《into the breach》合理掌握你的方寸之地
Flutter、GraphQL、PWA、WebAssembly……大前端時代,你需要掌握的那些技術
以色列公司 Cellebrite 掌握 iOS 漏洞,能為任何一支 iPhone 解鎖
掌握Photoshop中的雙色調效果
從 Zero到Hero,一文帶你完全掌握 Python
Integer類掌握了多少?
掌握結合臨床so easy
蘋果無語:美國FBI掌握輕鬆破解iPhone的方法
Python程序員為什麼一定要掌握Linux?
血液ctDNA-EGFR標準化檢測,三個關鍵環節全掌握
遠離報錯煩惱!深入全面掌握.NET Framework
NYPD:掌握很多關於Weinstein的關鍵證據,準備逮捕
北美Finance求職最佳路徑,從簡歷到面試全掌握!
掌握消防考試中的四大題型,滿分就是so easy!