JavaSE基礎(十) - 內部類 ??

內部類

今天接觸了一天的 Java 內部類,這個東西給我感覺一點就是:變化多端。之所以說這個東西變化多端,后面我們會用一些例子來證明,通過不同的形式來實現同一個方法。

內部類,可以分為以下四種

  • 成員內部類:創建在類內方法外,和成員變量及成員方法類似。
  • 局部內部類:創建在方法內部,類似局部代碼塊。
  • 靜態內部類:static 修飾的內部類。
  • 匿名內部類:也叫匿名子類對象,最特殊也是最常用的一種類型;一般用在方法參數的位置,匿名子類對象的類內方法也叫做 閉包

1.創建內部類類對象格式

  • 如果我們想訪問一個內部類時,我們需要通過外部類名.內部類名來找到這個內部類。
  • 在我們創建下面??這個內部類對象的格式是這樣的:外部類.內部類 對象名 = 外部類對象.內部類對象
class Outer {

    class Inner {

        public void method() {
            System.out.println("Hello Inner");
        }
    }
}

class Sample_InnerClass01 {

    public static void main(String[] args) {
        // 外部類.內部類 對象名 = 外部類對象.內部類對象;
        Outer.Inner oi = new Outer().new Inner();
        oi.method();
    }
}

Tip??:直接通過這種方式在創建內部類對象是不常用、也不推薦的方式,下面我們會介紹其他調用內部類的方式。


2.成員內部類私有的使用

  • 我們知道面向對象一個重要原則是封裝,就像我們會私有化成員變量一樣,在一般情況下內部類也是需要進行私有化,并提供外部訪問接口。
  • Sample 中我們私有化了 Inner 內部類,提供了 print 方法供外部調用。
class Outer {

    private int num = 10;

    private class Inner {
        public void method() {
            System.out.println("Print: " + num);
        }
    }

    public void print() {
        Inner in = new Inner();
        in.method();
    }
}

class Sample_InnerClass02 {

    public static void main(String[] args) {
        Outer o = new Outer();
        o.print();
    }
}

Thinking???♂?:本例中為什么內部類能訪問到外部類的成員變量?


3.靜態成員內部類

  • 與創建非靜態內部類對象不同的是,創建內部類對象格式有些不同。
  • 靜態內部類對象創建格式:外部類.內部類 對象名 = 外部類名.內部類對象
class Outer {

    private static int num = 10;

    static class Inner {
        public void method() {
            System.out.println("Print: " + num);
        }
    }
}

class Sample_InnerClass03 {

    public static void main(String[] args) {
        // 外部類.內部類 對象名 = 外部類名.內部類對象;
        Outer.Inner oi = new Outer.Inner();
        oi.method();
    }
}

Reminder?????:靜態內部類中只能訪問本類的靜態成員。


4.成員內部類的小練習??

  • 內部類之所以能獲取到外部類的成員,是因為它能獲取到外部類的引用 外部類名.this
class Outer {

    public int num = 10;

    class Inner {
         public int num = 20;

         public void show() {
            int num = 30;
            System.out.println(num);            // 30
            System.out.println(this.num);       // 20
            // 內部類之所以能獲取到外部類的成員,是因為它能獲取到外部類的引用 外部類名.this
            System.out.println(Outer.this.num); // 10
         }
    }
}

class Sample_InnerClass04 {

    public static void main(String[] args) {
        new Outer().new Inner().show();
    }
}

5.局部內部類訪問局部變量

  • 在內存中 num 會隨著 method 方法的出棧而釋放,而內部類在堆區還沒有消失。JVM 默認為局部變量添加 final ,其實是將 num復制 了一份提供給局部內部類來訪問,而之前真正的局部變量 num 已經被釋放,所以此時將局部變量用 final 修飾為一個常量。
  • 如果在內部類中改變 num 的值就會出現這樣的錯誤提示:錯誤: 從內部類引用的本地變量必須是最終變量或實際上的最終變量
class Outer {

    public void method() {

        int num = 10;   // 在 JDK1.8之后 JVM 會自動加上 final 修飾符

        class Inner {
            public void print() {
                System.out.println(num);
            }
        }

        Inner in = new Inner();
        in.print();
    }
}

class Sample_InnerClass05 {

    public static void main(String[] args) {
        new Outer().method();
    }
}

6.匿名子類對象概述

  • 概述:實際就是內部類的簡化寫法。
  • 前提:存在一個 接口 ,這里的類可以是具體類也可以是抽象類。
  • 格式:
new 類名或接口() {
    重寫方法;
}
  • 本質:是一個繼承了該類 或 者實現了該接口的 匿名子類對象
interface Inter {
    public abstract void print1();
}

class Outer {

    public void method() {
        Inter in = new Inter() {
            public void print1() {
                System.out.println("Print1");
            }
        };

        in.print1();
    }
}

class Sample_InnerClass06 {

    public static void main(String[] args) {
        new Outer().method();
    }
}

7.匿名子類對象重寫多個方法的調用

  • 使用原則:匿名子類對象只針對重寫一個方法的時候使用。
  • 弊端:不能定義、調用子類特有的方法,且沒有子類類名。
interface Inter {

    public void show1();

    public void show2();
}

class Outer {

    public void method() {

        Inter in = new Inter() {    // 父類引用指向子類對象(多態)

            public void show1() {
                System.out.println("show1");
            }

            public void show2() {
                System.out.println("show2");
            }
        };

        in.show1();
        in.show2();
        System.out.println(in);
    }
}

class Sample_InnerClass07 {

    public static void main(String[] args) {
        new Outer().method();
    }
}

Discussion??:Inter 父類指向匿名子類對象,其實是一個多態,如果在子類對象中定義了父類中不存在的方法,則編譯會報錯。而如果創建一個子類對象來實現接口方法的話,就可以擴展子類特有的功能了。


8.接口對象作為參數傳遞的多種實現形式

interface Inter {
    void print();
}

class Demo {
    public static void method(Inter i) {
        i.print();
    }
}

class InterClass implements Inter {
    public void print() {
        System.out.println("Hello World1!");
    }
}

class Test {

    private static final Inter i3;

    static {
        i3 = new Inter() {
            public void print() {
                System.out.println("Hello World3!");
            }
        };
    }

    public static void main(String[] args) {
        // 1.創建一個實現接口的子類對象。
        InterClass i1 = new InterClass();
        Demo.method(i1);
        
        // 2.在方法中創建一個匿名子類并返回。
        Inter i2 = method();
        Demo.method(i2);
        
        // 3.定義一個 Inter類型的 static 成員變量,并在構造代碼塊中用賦值它的子類對象。
        Demo.method(i3);

        // 4.在成員方法的參數位置創匿名子類對象,并重寫父類方法。(推薦方式)
        Demo.method(new Inter() {
            public void print() {
                System.out.println("Hello World4!");
            }
        });
    }

    public static Inter method() {
        return new Inter() {
            public void print() {
                System.out.println("Hello World2!");
            }
        };
    }
}

Discussion??:可以看到,通過子類實現 抽象類接口 的方式千變萬化,語法的掌握是基礎,但最終目的是為了提高代碼的內聚性、減少耦合性并簡化代碼,只有從這個目的出發去使用我們的內部類才能讓我們的編程能力得到提高。


9.悄悄話

  • 這是我個人發表的第 2 篇簡書 Blog,第一篇文章 JavaSE 基礎(六)構造函數 試著投了首頁和幾個關于 Java 的專題,都順利通過了,甚至還被專題推薦了文章,真的是沒想到的。今天寫這篇技術 Blog 完全是受著大家的鼓勵而寫出來的。
  • 因為這段時間本人正在 JavaSE 的閉關修行中,沒有太多時間去查閱相關資料和做文章優化,所以有些內容可能會有差錯,也請讀者們在評論中批評并指出問題。
  • 今天開通了簡書專題 JavaSE 成長之路,主要為一樣正在 JavaSE 修行中的簡友們提供了技術交流的平臺,希望大家多多投稿交流互動。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容

  • 一:java概述:1,JDK:Java Development Kit,java的開發和運行環境,java的開發工...
    ZaneInTheSun閱讀 2,671評論 0 11
  • 、6一、基本知識 1.JDK和JRE的區別 答:JDK是java語言開發工具包,包含JRE和開發工具(javac....
    夢游的沙師弟閱讀 1,214評論 0 4
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,707評論 18 399
  • 這個系列面試題主要目的是幫助你拿輕松到offer,同時還能開個好價錢。只要能夠搞明白這個系列的絕大多數題目,在面試...
    獨念白閱讀 348評論 0 3
  • 聽了一整天的課,看到楊老師的各種高端落地的各種項目,很受鼓舞。但問題也隨之而來: 1、如何解決眾籌項目和人員越來越...
    竇地主閱讀 360評論 0 0