一文了解Java的內部類

2020-12-13 程序釀造師

在Java中,類通常都是獨立存在的,但是我們可以在類中再定義類,這樣的類被稱為內部類。內部類定義位置的不同可以分為成員內部類、靜態內部類、方法內部類、匿名內部類。相對於內部類,包含內部類的類被稱為外部類。

1 內部類的意義

內部類從字面上是非常容易理解的,無非就是在類的內部定義的類。那麼為什麼要在類的內部再定義類呢?

1.私有變量訪問:我們可以把內部類當成外部類的一個成員,內部類對於外部類的其它私有成員變量來說是不受訪問控制權限所影響的。那麼內部類就實現了跨域訪問的特性。

2.隱藏式的多繼承:這個多繼承不同於接口的"多繼承",而是實實在在的多繼承。內部類也是一個單獨類,既然是類就有面向對象的特性,它就可以進行繼承操作,並且內部類的繼承操作對於外部類是否發生過繼承是沒有影響的。這樣內部類和外部類就共同實現了多繼承操作(如果內部類中還有內部類,繼承的個數會被擴大下去)。

3.可以作為抽象類、接口的匿名實現。一些接口和抽象類中的抽象方法非常少,單獨的創建實現子類非常的麻煩,我們就可以通過匿名內部類的方式直接實現接口或者抽象類,這樣能夠簡化類的設計過程。例如Swing中的事件處理、函數式接口都可以直接通過內部類來實現。

2 內部類種類及定義

在定義內部類時,內部類定義的位置不同其意義也不相同。內部類大體上可以分為四種類型:成員內部類,靜態內部類,局部內部類、匿名內部類。其中成員內部類和靜態內部類都是直接定義在外部類中,它們可以作為單獨的類被外部其它類所訪問(受限於訪問修飾符)。局域內部類和匿名內部類定義在方法中,它們並不會被外部的類所訪問,只是一種臨時類。

2.1 成員內部類

成員內部類,直接定義在類的內部,與類的成員變量和方法屬於同一層級。下面代碼是成員內部類的定義示例。

在上述代碼示例中,Inner就是一個內部類,包含Inner類的Outer類我們稱之為外部類。Inner類就是典型的成員內部類。成員內部類可以用常用的四種訪問控制修飾符進行修飾,其訪問控制與成員變量的訪問控制修飾一致。

在其它外圍類中,創建內部類與普通類是相似的,可以直接進行實例化操作。如果在其它外圍類中要完成對內部類Inner的實例創建,必須在外圍類中建立Outer對象,再由Outer對象來創建內部類Inner(如下面代碼所示)。

由於Inner內部類定義時採用了默認的訪問修飾,所以務必保證上述代碼所屬的類與Outer類在同一包中。在外圍類中使用內部類時,要注意內部類的訪問修飾,如果內部類是private修飾的,只能在外部類中使用,其它類是無法聲明內部類的。

2.2 靜態內部類

內部成員類被static修飾就變成了靜態內部類,靜態內部類可以直接進行聲明並實例化(如下面代碼所示)。

在上述代碼中,Inner類就是一個靜態內部類,靜態內部類同樣也可以用四種類型的訪問控制符進行修飾。訪問規則與成員變量訪問控制修飾規則一樣。

外部類對靜態內部類的訪問與成員內部類的訪問方式一樣,直接實例化即可。靜態內部類和成員內部類在使用上的區別主要是在創建過程中存在著差異。

2.3 局部內部類

具備內部類是定義在外部類中的方法中(或流程控制語句中)。局部內部類不能被外部類和外圍類訪問,它只能在定義的局部位置使用(參考局部變量的使用,定義和使用見下面代碼示例)。

在上述代碼示例中,showInner()方法中定義的Inner就是一個方法局部內部類,方法局部內部類只能在方法中使用,出了方法就不能被使用。在showInner2()方法中,Inner2是一個流程控制局部類,它只能在流程內使用。

局部類與局部變量擁有一樣的生命周期,與局部變量一樣,不能被訪問控制修飾符進行修飾。

2.4 匿名內部類

匿名內部類是局部內部類最常用的一種表現形式。匿名內部類只有類的實現體,而沒有類的方法。

我們知道接口(抽象類)是不能直接實例化的,我們必須通過實例化它們的子類來間接的完成接口(抽象類)的實例化。而匿名內部類 相當於我們在使用接口(抽象類)時,臨時創造了一個子類,但是這個子類我們沒有給它命名,我們稱之為匿名類。通常這樣的類是在方法調用過程中創建並使用的(下面代碼演示了匿名內部類的使用)。

在上述示例中,我們在main方法中直接實例化抽象類Animal,在實例化的過程中我們實現了一個匿名的內部類,並將Animal中的抽象方法eat實現。實際上dog對象引用的就是我們創建的匿名內部類。

3 內部類的外部訪問

內部類對外部類可以進行無縫的訪問,無視外部類的訪問修飾。在類的實例方法中,如果類的成員變量和局部變量發生重名衝突時,使用this關鍵字可以表示當前對象。

在內部類中使用"this.變量名"方式表示內部類的成員變量,而外部類的成員變量則用"外部類名.this.變量名"的方式表示外部類的成員變量(如下面代碼所示)。

在上述代碼示例中,內部類getInnerName方法中,我們用this關鍵字對內部類的成員變量進行返回操作,在getOuterName方法中,我們使用Outer.this對外部類的成員變量進行操作。

對於靜態內部類,它的外部訪問比較特殊,靜態內部類只能訪問外部類的靜態變量。而且靜態的內部類中,不能創建靜態的類變量。

每周定時發布2篇基礎技術文章或案例,謝謝關注。

相關焦點

  • 一文讀懂JAVA類文件結構
    有些人說了類文件結構我們知道或者不知道沒有什麼作用,如果你持有這種觀點,我覺得需要矯正一下,類文件結構是沒有多大的作用,但是它是我們代碼和java虛擬機之間的橋梁,如果研究透了類文件結構,那麼會對我們研究虛擬機的運行起到至關重要的作用,同樣對於我們研究jvm內存調優能夠帶來很大的幫助。
  • Java中內部類到底有什麼用?
    java中內部類種類較多,語法比較複雜,用法也不盡相同。概括下來,可以分類為以下五種內部類。內部類嵌套內部類局部內部類接口內部類匿名內部類本篇文章只對實際項目開發中用的較多的,普通內部類與匿名內部類做一定介紹。其他三種若有興趣請自行通過谷歌或書籍進行了解。
  • Java內部類新解,你沒有見過的船新版本
    用圖表示分類及關係如下:上面是按照官方的說法來分的,實際中很多人習慣把所有的嵌套類都稱為inner class(內部類),這只是個稱謂,不影響溝通就好。後文用nested class來統稱static nested class和non-static nested class。各個類的主要特性和限制已經在圖中說明了(適用於JDK 8及以後)。
  • Java提高篇——詳解內部類
    可以將一個類的定義放在另一個類的定義內部,這就是內部類。內部類是一個非常有用的特性但又比較難理解使用的特性(鄙人到現在都沒有怎麼使用過內部類,對內部類也只是略知一二)。第一次見面內部類我們從外面看是非常容易理解的,無非就是在一個類的內部在定義一個類。
  • 一文讓你明白 Java 字節碼
    Java號稱是一門「一次編譯到處運行」的語言,但是我們對這句話的理解深度又有多少呢?從我們寫的java文件到通過編譯器編譯成java字節碼文件(也就是.class文件),這個過程是java編譯過程;而我們的java虛擬機執行的就是字節碼文件。不論該字節碼文件來自何方,由哪種編譯器編譯,甚至是手寫字節碼文件,只要符合java虛擬機的規範,那麼它就能夠執行該字節碼文件。
  • 你真的了解java類加載器嗎?
    Java默認的類加載器通常可以分為三種:1.啟動類加載器(BootstrapClassLoader):jvm內部C++實現,無法獲取2.擴展類加載器(ExtClassLoader)3.應用程式類加載器(AppClassLoader)加載路徑各不同:1.BootstrapClassLoader加載Java核心API,即\jre\lib
  • Java匿名、靜態、非靜態、方法區內部類,忘記了,一塊學習下
    01 內部類的定義在java中內部類是將一個類定義在另一個類的方法或者類中,這樣的類我們稱它為內部類。內部類可以分為四種:局部內部類、成員內部類、匿名內部類、靜態內部類,下面我們逐一介紹這四種內部類。它與成員內部類的區別在於局部內部類的訪問權限僅限於方法或作用域內。
  • java 核心類一
    一. String去除首尾空白字符使用trim()方法可以移除字符串首尾空白字符。
  • 一文告訴你Java日期時間API到底有多爛
    下面就來具體了解下它有哪些坑爹的設計和槽點,一起不吐不快。日期時間API的七宗罪針對這種case,一般來說我們函數內部操作的參數只能是副本:要麼調用者傳進來的就是副本,要麼內部自己生成一個副本。所以說,把Date設計為一個可變的類是非常糟糕的設計。罪狀四:無法理喻的java.sql.Date來,看看java.util.Date類的繼承結構:
  • java基礎入門-day10-內部類概述
    內部類概述在一個類的內部再定義一個類。這就形成了外部類和內部類!2 成員內部類所有稱呼為成員的東西都是被類體直接包含的東西。3 一般內部類都是私有的一般一個內部類都是私有的!也就是說,內部類只能被外部類使用。4 內部類訪問外部類成員內部類中可以直接訪問外部類成員,包含私有成員。
  • 阿里內部員工,排查Java問題常用的工具單
    utm_content=m_10360這是一篇來源於阿里內部技術論壇的文章,原文在阿里內部獲得一致好評。作者已經把這篇文章開放到雲棲社區中供外網訪問。文章內容做了部分刪減,主要刪減掉了其中只有阿里內部才能使用的工具的介紹,並刪減掉部分只有通過阿里內網才能訪問到的連結。
  • Java之成員內部類詳解
    前言在上文中,講到了靜態內部類,本文主要談一下成員內部類、局部內部類和匿名內部類。成員內部類和靜態內部類非常相似,都是定義在一個類中的成員位置,與靜態內部類唯一的區別是,成員內部類沒有static修飾。或者也可以這麼理解:我們知道一個類有成員變量、有成員方法,那麼這些成員定義在類中的哪個位置,那麼成員內部類也就定義在哪個位置。
  • Java基礎知識中的類
    Java類的內容一、類的定義和聲明Java程式語言是面向對象的,處理的最小的完整單元為對象。而現實生活中具有共同特性的對象的抽象就稱之為類。類由類聲明和類體構成,類體又由變量和方法構成。下面給出一個例子來看一下類的構成。
  • 一文帶你全面了解Java 序列化
    實現第一步,則需要的先將對象實例相關的類標記為需要序列化。JDK類庫中序列化和反序列化APIjava.io.ObjectInputStream:對象輸入流該類中的readObject()方法從輸入流中讀取字節序列,然後將字節序列反序列化為一個對象並返回。
  • 給Java新手的一些建議——Java知識點歸納(Java基礎部分)
    JVM相關(包括了各個版本的特性)對於剛剛接觸Java的人來說,JVM相關的知識不一定需要理解很深,對此裡面的概念有一些簡單的了解即可。不過對於一個有著3年以上Java經驗的資深開發者來說,不會JVM幾乎是不可接受的。JVM作為java運行的基礎,很難相信對於JVM一點都不了解的人可以把java語言吃得很透。
  • java類加載的過程概述
    任何類被使用時系統都會建立一個Class對象。2. 連接:(1)驗證是否有正確的內部結構,並和其他類協調一致。(2)準備負責為類的靜態成員分配內存,並設置默認初始化值。(3)解析將類的二進位數據中的符號引用替換為直接。
  • Java基礎教程:java反射機制教程
    一、反射概念 在正式講解反射之前,為了很好的去理解它我們先從一個案例說起。請看下面的代碼: 現在出現一個問題,如果這個user類不是我們自己定義的,我們從外部看不到裡面有什麼東西,而且我們又想去知道內部長什麼樣,比如說有幾個欄位、方法、構造方法、共有還是私有的等等,這時候該怎麼辦呢?這時候java語言在設計的時候為我們提供了一個機制,就是反射機制,他能夠很方便的去解決我們的問題。
  • 跟我學java編程—Java的Scanner類
    可以通過Scanner類方便地獲取用戶輸入。通過Scanner類獲取用戶輸入時,控制臺會一直等待用戶的輸入,直到用戶敲回車鍵結束,把所輸入的內容傳給Scanner,程序要從Scanner獲取輸入的內容,則只需要調用Scanner的nextLine()方法即可。
  • 再來說說Java嵌套類(nested class)
    【IT168 文檔】有時候開發時為了方便,在代碼中使用了不少嵌套類(nested class),但是使用過程中如果不了解嵌套類的特性,可能會造成意想不到的情況。  Java對象想要通過網絡傳輸,必須實現序列化接口,於是我們在Service中定義了了一個實現了序列化接口的內部類,然後調用遠程接口將其傳輸到網絡上。
  • java面試題總結:java的接口類和抽象類的特點
    java的接口類和抽象類的特點java中抽象類的特點: