JavaSE基礎(chǔ)(十) - 內(nèi)部類 ??

內(nèi)部類

今天接觸了一天的 Java 內(nèi)部類,這個(gè)東西給我感覺(jué)一點(diǎn)就是:變化多端。之所以說(shuō)這個(gè)東西變化多端,后面我們會(huì)用一些例子來(lái)證明,通過(guò)不同的形式來(lái)實(shí)現(xiàn)同一個(gè)方法。

內(nèi)部類,可以分為以下四種

  • 成員內(nèi)部類:創(chuàng)建在類內(nèi)方法外,和成員變量及成員方法類似。
  • 局部?jī)?nèi)部類:創(chuàng)建在方法內(nèi)部,類似局部代碼塊。
  • 靜態(tài)內(nèi)部類:static 修飾的內(nèi)部類。
  • 匿名內(nèi)部類:也叫匿名子類對(duì)象,最特殊也是最常用的一種類型;一般用在方法參數(shù)的位置,匿名子類對(duì)象的類內(nèi)方法也叫做 閉包

1.創(chuàng)建內(nèi)部類類對(duì)象格式

  • 如果我們想訪問(wèn)一個(gè)內(nèi)部類時(shí),我們需要通過(guò)外部類名.內(nèi)部類名來(lái)找到這個(gè)內(nèi)部類。
  • 在我們創(chuàng)建下面??這個(gè)內(nèi)部類對(duì)象的格式是這樣的:外部類.內(nèi)部類 對(duì)象名 = 外部類對(duì)象.內(nèi)部類對(duì)象
class Outer {

    class Inner {

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

class Sample_InnerClass01 {

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

Tip??:直接通過(guò)這種方式在創(chuàng)建內(nèi)部類對(duì)象是不常用、也不推薦的方式,下面我們會(huì)介紹其他調(diào)用內(nèi)部類的方式。


2.成員內(nèi)部類私有的使用

  • 我們知道面向?qū)ο笠粋€(gè)重要原則是封裝,就像我們會(huì)私有化成員變量一樣,在一般情況下內(nèi)部類也是需要進(jìn)行私有化,并提供外部訪問(wèn)接口。
  • Sample 中我們私有化了 Inner 內(nèi)部類,提供了 print 方法供外部調(diào)用。
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???♂?:本例中為什么內(nèi)部類能訪問(wèn)到外部類的成員變量?


3.靜態(tài)成員內(nèi)部類

  • 與創(chuàng)建非靜態(tài)內(nèi)部類對(duì)象不同的是,創(chuàng)建內(nèi)部類對(duì)象格式有些不同。
  • 靜態(tài)內(nèi)部類對(duì)象創(chuàng)建格式:外部類.內(nèi)部類 對(duì)象名 = 外部類名.內(nèi)部類對(duì)象
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) {
        // 外部類.內(nèi)部類 對(duì)象名 = 外部類名.內(nèi)部類對(duì)象;
        Outer.Inner oi = new Outer.Inner();
        oi.method();
    }
}

Reminder?????:靜態(tài)內(nèi)部類中只能訪問(wèn)本類的靜態(tài)成員。


4.成員內(nèi)部類的小練習(xí)??

  • 內(nèi)部類之所以能獲取到外部類的成員,是因?yàn)樗塬@取到外部類的引用 外部類名.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
            // 內(nèi)部類之所以能獲取到外部類的成員,是因?yàn)樗塬@取到外部類的引用 外部類名.this
            System.out.println(Outer.this.num); // 10
         }
    }
}

class Sample_InnerClass04 {

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

5.局部?jī)?nèi)部類訪問(wèn)局部變量

  • 在內(nèi)存中 num 會(huì)隨著 method 方法的出棧而釋放,而內(nèi)部類在堆區(qū)還沒(méi)有消失。JVM 默認(rèn)為局部變量添加 final ,其實(shí)是將 num復(fù)制 了一份提供給局部?jī)?nèi)部類來(lái)訪問(wèn),而之前真正的局部變量 num 已經(jīng)被釋放,所以此時(shí)將局部變量用 final 修飾為一個(gè)常量。
  • 如果在內(nèi)部類中改變 num 的值就會(huì)出現(xiàn)這樣的錯(cuò)誤提示:錯(cuò)誤: 從內(nèi)部類引用的本地變量必須是最終變量或?qū)嶋H上的最終變量。
class Outer {

    public void method() {

        int num = 10;   // 在 JDK1.8之后 JVM 會(huì)自動(dòng)加上 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.匿名子類對(duì)象概述

  • 概述:實(shí)際就是內(nèi)部類的簡(jiǎn)化寫(xiě)法。
  • 前提:存在一個(gè) 接口 ,這里的類可以是具體類也可以是抽象類。
  • 格式:
new 類名或接口() {
    重寫(xiě)方法;
}
  • 本質(zhì):是一個(gè)繼承了該類 或 者實(shí)現(xiàn)了該接口的 匿名子類對(duì)象。
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.匿名子類對(duì)象重寫(xiě)多個(gè)方法的調(diào)用

  • 使用原則:匿名子類對(duì)象只針對(duì)重寫(xiě)一個(gè)方法的時(shí)候使用。
  • 弊端:不能定義、調(diào)用子類特有的方法,且沒(méi)有子類類名。
interface Inter {

    public void show1();

    public void show2();
}

class Outer {

    public void method() {

        Inter in = new Inter() {    // 父類引用指向子類對(duì)象(多態(tài))

            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 父類指向匿名子類對(duì)象,其實(shí)是一個(gè)多態(tài),如果在子類對(duì)象中定義了父類中不存在的方法,則編譯會(huì)報(bào)錯(cuò)。而如果創(chuàng)建一個(gè)子類對(duì)象來(lái)實(shí)現(xiàn)接口方法的話,就可以擴(kuò)展子類特有的功能了。


8.接口對(duì)象作為參數(shù)傳遞的多種實(shí)現(xiàn)形式

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.創(chuàng)建一個(gè)實(shí)現(xiàn)接口的子類對(duì)象。
        InterClass i1 = new InterClass();
        Demo.method(i1);
        
        // 2.在方法中創(chuàng)建一個(gè)匿名子類并返回。
        Inter i2 = method();
        Demo.method(i2);
        
        // 3.定義一個(gè) Inter類型的 static 成員變量,并在構(gòu)造代碼塊中用賦值它的子類對(duì)象。
        Demo.method(i3);

        // 4.在成員方法的參數(shù)位置創(chuàng)匿名子類對(duì)象,并重寫(xiě)父類方法。(推薦方式)
        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??:可以看到,通過(guò)子類實(shí)現(xiàn) 抽象類接口 的方式千變?nèi)f化,語(yǔ)法的掌握是基礎(chǔ),但最終目的是為了提高代碼的內(nèi)聚性、減少耦合性并簡(jiǎn)化代碼,只有從這個(gè)目的出發(fā)去使用我們的內(nèi)部類才能讓我們的編程能力得到提高。


9.悄悄話

  • 這是我個(gè)人發(fā)表的第 2 篇簡(jiǎn)書(shū) Blog,第一篇文章 JavaSE 基礎(chǔ)(六)構(gòu)造函數(shù) 試著投了首頁(yè)和幾個(gè)關(guān)于 Java 的專題,都順利通過(guò)了,甚至還被專題推薦了文章,真的是沒(méi)想到的。今天寫(xiě)這篇技術(shù) Blog 完全是受著大家的鼓勵(lì)而寫(xiě)出來(lái)的。
  • 因?yàn)檫@段時(shí)間本人正在 JavaSE 的閉關(guān)修行中,沒(méi)有太多時(shí)間去查閱相關(guān)資料和做文章優(yōu)化,所以有些內(nèi)容可能會(huì)有差錯(cuò),也請(qǐng)讀者們?cè)谠u(píng)論中批評(píng)并指出問(wèn)題。
  • 今天開(kāi)通了簡(jiǎn)書(shū)專題 JavaSE 成長(zhǎng)之路,主要為一樣正在 JavaSE 修行中的簡(jiǎn)友們提供了技術(shù)交流的平臺(tái),希望大家多多投稿交流互動(dòng)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一:java概述:1,JDK:Java Development Kit,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工...
    ZaneInTheSun閱讀 2,826評(píng)論 0 11
  • 、6一、基本知識(shí) 1.JDK和JRE的區(qū)別 答:JDK是java語(yǔ)言開(kāi)發(fā)工具包,包含JRE和開(kāi)發(fā)工具(javac....
    夢(mèng)游的沙師弟閱讀 1,379評(píng)論 0 4
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,898評(píng)論 18 399
  • 這個(gè)系列面試題主要目的是幫助你拿輕松到offer,同時(shí)還能開(kāi)個(gè)好價(jià)錢。只要能夠搞明白這個(gè)系列的絕大多數(shù)題目,在面試...
    獨(dú)念白閱讀 407評(píng)論 0 3
  • 聽(tīng)了一整天的課,看到楊老師的各種高端落地的各種項(xiàng)目,很受鼓舞。但問(wèn)題也隨之而來(lái): 1、如何解決眾籌項(xiàng)目和人員越來(lái)越...
    竇地主閱讀 391評(píng)論 0 0

友情鏈接更多精彩內(nèi)容