1. 程式人生 > >Java內部類超詳細總結(含程式碼示例)

Java內部類超詳細總結(含程式碼示例)

什麼是內部類

什麼是內部類?
顧名思義,就是將一個類的定義放在另一個類的內部。
概念很清楚,感覺很簡單,其實關鍵在於這個內部類放置的位置,可以是一個類的作用域範圍、一個方法的或是一個程式碼塊的作用域範圍。
所以理解了概念只是第一步,掌握細節才能徹底搞定Java的內部類特性。
看例子,這是最普通的內部類:

public class Product1 {
    class Design{
        private String name = "P30 pro";
        public String showName() {
            return name;
        }
    }

    class Content{
        private int i;
        Content(int value){
            i = value;
        }
        int value() {return i;}
    }
    public void show(int value) {
        Content c = new Content(value);
        Design d = new Design();
        System.out.println(d.showName());
        System.out.println(c.value());
    }
    public static void main(String[] args) {
        Product1 p = new Product1();
        p.show(6000);
    }
}

說明:
上面這個示例展示了內部類最基礎的用法,就是將一個或多個類的定義放在了外圍內的內部。可以看到在show()方法中的使用和普通類一樣,沒有區別。

另外,在外圍類的非靜態方法之外的任意位置,不能通過直接new 內部類的方式建立內部類物件。會報編譯錯誤。
像這樣:

還有這樣:

如果想要在外圍類非靜態方法之外建立內部類物件。怎麼辦呢?

正確的姿勢是這樣子:
在外圍類中增加兩個公共方法,返回內部類的引用。

    public Design design() {
        return new Design();
    }
    public Content content(int value) {
        return new Content(value);
    }

然後通過外部類物件呼叫方法的方式獲取內部類物件。

    public static void main(String[] args) {
        Product2 p = new Product2();
        p.show(6000);
        Product2.Content c1 = p.content(100);
        Product2.Design d1 = p.design();
    }

值得注意的是,外部類之外的其他類,也是不能直接訪問到該外部類的內部類物件的。
會報編譯錯誤。這也符合內部類的定義,就是為外圍類服務的嘛!

內部類的特性

1.可以連結到外部類

當生成一個內部類物件時,此物件與製造它的外圍物件之間就有了一種聯絡,所以它能訪問外圍物件的所有成員,而不需要任何特殊的條件。

下面的例子是《Java程式設計思想》中的示例
首先定義一個Selector介面

public interface Selector {
    boolean end();
    Object current();
    void next();
}

然後定義一個Sequence類,其中定義有一個private的內部類。

public class Sequence {

    private Object[] items;
    private int next = 0;
    public Sequence(int size) {items = new Object[size];}
    public void add(Object x) {
        if(next < items.length) {
            items[next++] = x;
        }
    }
    private class SequenceSelector implements Selector{
        private int i = 0;
        public boolean end() {
            return i == items.length;
        }
        public Object current() {
            return items[i];
        }
        public void next() {
            if(i < items.length) {i++;}
        }
    }
    public Selector selector() {
        return new SequenceSelector();
    }
    public static void main(String[] args) {
        Sequence sequence = new Sequence(10);
        for(int i = 0; i < 10; i++) {
            sequence.add(Integer.toString(i));
        }
        Selector selector = sequence.selector();
        while(!selector.end()) {
            System.out.print(selector.current() + " ");
            selector.next();
        }
    }
}

說明:
可以看到SequenceSelector是一個內部類,其end()、current()和next()都用到了外圍類中private的items欄位。

2.使用.this和.new

.this的用法
如果需要生成對外部類物件的引用,可以使用外部類的名字後面緊跟圓點和this。
如下所示:

public class DotThis {
    void name() {System.out.println("name");}
    public class Inner{
        public DotThis outer() {
            return DotThis.this;
        }
    }
    public Inner inner() {return new Inner();}
    public static void main(String[] args) {
        DotThis dt = new DotThis();
        DotThis.Inner inner = dt.inner();
        inner.outer().name();
    }
}

需要注意DotThis.this只是產生了正確的外部類引用。並沒有建立外部類物件。

.new的用法
可以通過該語法建立內部類物件,不過要注意的是要使用外部類的物件去建立。

public class DotNew {
    public class Inner{}
    public static void main(String[] args) {
        DotNew dn = new DotNew();
        DotNew.Inner dnInner = dn.new Inner();
    }
}

內部類分類

1、區域性內部類

定義在一個方法中或是方法中某一作用域內的類。稱作區域性內部類。

public class Product3 {
    public Section section(String inputName) {
        class ASection implements Section{
            private String name;
            private ASection(String name) {
                this.name = name;
            }
            @Override
            public String hello() {
                return name + " say hello";
            }
        }
        return new ASection(inputName);
    }
    public static void main(String[] args) {
        Product3 p = new Product3();
        Section section = p.section("aaaaa");
        System.out.println(section.hello());
    }
}

ASection是一個Section介面的實現,Section介面程式碼如下:

public interface Section {
    String hello();
}

說明:

  • 該內部類在section()方法中,該方法之外不能訪問ASection類;
  • 方法內部類不允許使用訪問許可權修飾符(public、private、protected);
  • 注意方法返回的是Section 的引用,即有向上轉型。

另外還可以將內部類的定義放在方法中某一語句塊中,如if語句塊中。

public class Product4 {

    public String check(boolean flag) {
        String checkId = null;
        if(flag) {
            class DetailCheck{
                private String id;
                private DetailCheck(String id) {
                    this.id = id;
                }
                String getId() {
                    return id;
                }
            }
            DetailCheck dc = new DetailCheck("1111");
            checkId = dc.getId();
        }
        return checkId;
    }
    public static void main(String[] args) {
        Product4 p = new Product4();
        System.out.println(p.check(true));
    }
}

說明:
DetailCheck內部類在if語句塊中,因此它的作用範圍也在if語句塊的範圍之內。超出該範圍是不可用的。比如這樣就會編譯報錯:

2、匿名內部類

匿名內部類其實是一種特殊的方法內部類(區域性內部類)。它特殊在於將內部類的定義和其物件建立結合在了一塊。沒有通過class關鍵字顯示宣告內部類名稱,故謂之“匿名”。
看程式碼示例:

public class Product5 {
    public Section section() {
        return new Section() {
            private String name = "hayli";
            @Override
            public String hello() {
                // TODO Auto-generated method stub
                return name + " haha";
            }
        };
    }
    public static void main(String[] args) {
        Product5 p = new Product5();
        p.section();
    }
}

說明:
此處Section可以是介面,也可是基類。

3、巢狀類(靜態內部類)

使用static關鍵字修飾的內部類,叫做靜態內部類,也稱作巢狀類。
巢狀類和普通內部類之間最大的區別是:

  • 普通內部類物件隱式地儲存了一個引用,指向建立它的外部類物件。而巢狀類建立物件,並不需要外部類物件。
  • 不能從巢狀類的物件中訪問非靜態的外部類物件。
  • 普通內部類不能有static資料和static欄位,也不能包含巢狀類,但是巢狀類可以包含所有這些東西。
public class Product6 {
    private static int id = 100;
    private static class BSection implements Section{
        private String name = "bbbb";
        @Override
        public String hello() {
            return name + " hello";
        }
        // 只能訪問外部類的靜態資料或欄位
        public int getId() {return id;}
        
        // 可以包含靜態資料或方法
        static int x = 200;
        public static void test1() {}
        
        // 可以再巢狀一層
        static class BInner{
            private String name;
            static void test1() {System.out.println("inner ===");}
        }
    }
    public static void main(String[] args) {
        Section section = new BSection();
        section.hello();
    }

總結

本篇介紹了什麼是內部類、內部類最普通定義方法和Java內部類的幾種具體型別詳解。雖然工作中使用內部類的機會不會,但是瞭解這些最基礎的知識,真的在專案中遇到內部類的寫法,也能看懂是怎麼回事了。

掃碼關注微信公眾號:二營長的筆記。回覆“二營長”,可領取Java相關技術資料。

相關推薦

Java部類詳細總結程式碼示例

什麼是內部類 什麼是內部類? 顧名思義,就是將一個類的定義放在另一個類的內部。 概念很清楚,感覺很簡單,其實關鍵在於這個內部類放置的位置,可以是一個類的作用域範圍、一個方法的或是一個程式碼塊的作用域範圍。 所以理解了概念只是第一步,掌握細節才能徹底搞定Java的內部類特性。 看例子,這是最普通的內部類: pu

java提高篇拓展篇 java知識彙總---IO流的使用規律總結程式碼示例淺顯易懂

IO流的使用規律總結。 解決的問題,就是在開發過程中具體要使用哪個流物件的問題。 1,明確 資料來源,資料匯(資料的目的)其實就是在明確要使用的IO體系,InputStream OutputStream Reader Writer需求中操作的是源:意味著是 讀。InputS

C語言操作符總結程式碼講解

C語言基本操作符分為算術操作符、移位操作符、位操作符、賦值操作符、複合賦值符、單目操作符、關係操作符、邏輯操作符、條件操作符、逗號表示式、下表引用、函式呼叫、結構成員。 算術操作符:+(加) - (減) *

十大經典排序算法詳細總結JAVA代碼實現

出現的次數 完全 放置 累加 有時 經典 整數 eap 分割 原文出處:http://mp.weixin.qq.com/s/feQDjby4uYGRLbYUJq7Lpg 0、排序算法說明 0.1 排序的定義 對一序列對象根據某個關鍵字進行排序。 0.2 術

各大公司Java面試題詳細總結

各大公司Java面試題超詳細總結 ThreadLocal(執行緒變數副本) Synchronized實現記憶體共享,ThreadLocal為每個執行緒維護一個本地變數。 採用空間換時間,它用於執行緒間的資料隔離,為每一個使用該變數的執行緒提供一個副本,每個執行緒都可以獨立地改變自己的副本,而不會

機器學習筆試面試詳細總結

51、概率和資訊量的關係 示例: 符號集 a 、 b 、 c 、 d ,它們相互獨立,相應概率為 1/2 、 1/4 、 1/8/ 、 1/16 ,其中包含資訊量最小的符號(a) 解析: 訊息出現的概率越小,說明限制條件越多,則訊息中所包含的資訊量就越大;

Java面試題詳細總結

1:ThreadLocal(執行緒變數副本) Synchronized實現記憶體共享,ThreadLocal為每個執行緒維護一個本地變數。 採用空間換時間,它用於執行緒間的資料隔離,為每一個使用該變數的執行緒提供一個副本,每個執行緒都可以獨立地改變自己的副本,而

Django的ListView詳細用法分頁paginate功能

# 開發環境: python 3.6 django 1.11 # 場景一 經常有從資料庫中獲取一批資料,然後在前端以列表的形式展現,比如:獲取到所有的使用者,然後在使用者列表頁面展示。 # 解決方案 常規寫法是,我們通過Django的ORM查詢到所有的資料,然後展示出來,程式碼如下: ```python

Java 小練習—使用者註冊登入異常處理

需求: A: 請選擇要使用的功能 1. 登入 請輸入賬號 請輸入密碼 呼叫 B 的方法獲取登入結果 登入成功/登入失敗 2. 註冊 請輸入賬號 請輸入密碼 呼叫 B 的方法獲取註冊結果 註冊成功/註冊失敗

OCJP 1Z0-808考題詳細解析word文件 題1--30

題目難度分類 個人對於題目難度的分類:難度總共五星 不理解題:   ★★★★★ 閱讀理解題:  ★★★★ 難點題: ★★★ 套路題:      ★★★ 基礎題/送分題:    

OCJP 1Z0-808考題詳細解析word文件 題50--60

我現在邊工作,業餘時間看看,更新的可能的比較慢,望大家諒解。 題58 Given the code fragment:  if(aVar++ < 10){ System.out.println(aVar+ " Hello

Java併發之Lock第一季synchronized對比

1、簡單回顧一下synchronized a、一個Java中的關鍵字 b、一個普通程式碼塊被synchronized修飾,那麼鎖就是當前物件,當一個執行緒物件A獲得了物件鎖,並執行該程式碼塊時,其他的執行緒物件B或其他名字,便會一直等待,一直等待執行緒A釋放鎖 c、執行緒A在什麼情況

《深入理解JAVA虛擬機器》詳細解讀第三章 :垃圾收集器與記憶體分配策略

  目錄 一、垃圾收集器與記憶體分配策略 1 概述 2 物件已經死亡? 2.1引用計數法(未使用) 2.2可達性分析演算法 2.3 再談引用 2.4 生存還是死亡 2.5 回收方法區 3 垃圾收集演算法 3.1 複製演算法(Copy) 3

Mahout機器學習平臺之聚類演算法詳細剖析例項分析

第一部分: 學習Mahout必須要知道的資料查詢技能: 學會查官方幫助文件: 解壓用於安裝檔案(mahout-distribution-0.6.tar.gz),找到如下位置,我將該檔案解壓到win7的G盤mahout資料夾下,路徑如下所示: G:\mahout\mahout

[Java]《Java程式設計思想》知識點總結堅持逐步更新

第1章 1.抽象與物件:程式語言提供抽象機制,解決問題的複雜性取決於抽象的型別和質量。“型別”指“所抽象的是什麼”。 應只針對待解決的問題建模。面向物件方式提供表示問題空間中的元素的工具,將問題空間中的元素及其在解空間中的表示稱為”物件“。 程式可通過新增新型別的物件使自身

ml課程:概率圖模型—貝葉斯網路、隱馬爾可夫模型相關程式碼實現

以下是我的學習筆記,以及總結,如有錯誤之處請不吝賜教。 本文主要介紹機器學習中的一個分支——概率圖模型、相關基礎概念以及樸素貝葉斯、隱馬爾可夫演算法,最後還有相關程式碼案例。 說到機器學習的起源,可以分為以下幾個派別: 連線主義:又稱為仿生學派(bionicsism)或生理學派

ml課程:最大熵與EM演算法及應用程式碼實現

以下是我的學習筆記,以及總結,如有錯誤之處請不吝賜教。 本文主要介紹最大熵模型與EM演算法相關內容及相關程式碼案例。 關於熵之前的文章中已經學習過,具體可以檢視:ml課程:決策樹、隨機森林、GBDT、XGBoost相關(含程式碼實現),補充一些 基本概念: 資訊量:資訊的度量,即

ml課程:SVM相關程式碼實現

以下是我的學習筆記,以及總結,如有錯誤之處請不吝賜教。 本文主要介紹svm的創始人Vapnik‘s如何一步一步構建出這個經典演算法模型的,同時也可以給我們以後演算法之路提供一個思路,即使你對優化等數學方法不熟悉,依然可以創造出很好的演算法。 下svm關鍵的幾個idea: KEY ID

ml課程:決策樹、隨機森林、GBDT、XGBoost相關程式碼實現

以下是我的學習筆記,以及總結,如有錯誤之處請不吝賜教。 基礎概念: 熵Entropy:是衡量純度的一個標準,表示式可以寫為: 資訊增益Information Gain:熵變化的一個量,表示式可以寫為: 資訊增益率Gain Ratio:資訊增益的變化率,表示式可以寫為:

ml課程:線性迴歸、邏輯迴歸入門程式碼實現

以下是我的學習筆記,以及總結,如有錯誤之處請不吝賜教。 本文主要介紹簡單的線性迴歸、邏輯迴歸先關推倒,以及案例程式碼。 昨天做專案發現K-means都忘了,想想之前很多基礎都忘了,於是決定重新開始學一遍ml的基礎內容,順便記錄一下,也算是梳理自己的知識體系吧。 機器學習:目前包括有監