Java & Groovy & Scala & Kotlin - 17.內(nèi)部類(lèi)

Overview

所謂的內(nèi)部類(lèi)即定義在類(lèi)內(nèi)部的類(lèi)拯辙,而包含這個(gè)內(nèi)部類(lèi)的類(lèi)則被稱(chēng)作外部類(lèi)。通常來(lái)說(shuō)內(nèi)部類(lèi)可以訪(fǎng)問(wèn)外部類(lèi)的私有成員,作為外部類(lèi)的內(nèi)部擴(kuò)展而存在吁脱。

Java 篇

靜態(tài)內(nèi)部類(lèi)

靜態(tài)內(nèi)部類(lèi)即以 static 關(guān)鍵字聲明的內(nèi)部類(lèi)。靜態(tài)內(nèi)部類(lèi)不屬于外部類(lèi)的成員彬向,使用上與普通的外部類(lèi)沒(méi)有什么區(qū)別兼贡。

定義一個(gè)靜態(tài)內(nèi)部類(lèi)

class Outter {
    static class StaticInner {
    }
}

創(chuàng)建靜態(tài)內(nèi)部類(lèi)的實(shí)例

Outter.StaticInner staticInner = new Outter.StaticInner();

匿名內(nèi)部類(lèi)

匿名內(nèi)部類(lèi)即沒(méi)有指明名字的內(nèi)部類(lèi),通常用于監(jiān)聽(tīng)器和線(xiàn)程的創(chuàng)建娃胆。

例:

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {

    }
});

以上 new Runnable() 即定義了一個(gè)沒(méi)有名字的實(shí)現(xiàn)了 Runnalbe 接口的內(nèi)部類(lèi)并立即創(chuàng)建該類(lèi)的實(shí)例作為 Thread 的構(gòu)造方法的參數(shù)遍希。

非靜態(tài)內(nèi)部類(lèi)

非靜態(tài)內(nèi)部類(lèi)屬于外部類(lèi),可以被看做為外部類(lèi)的一個(gè)成員里烦,和外部類(lèi)定義的普通方法和成員變量沒(méi)有什么區(qū)別凿蒜,所以在該內(nèi)部類(lèi)中可以訪(fǎng)問(wèn)外部類(lèi)的所有成員。也正是這個(gè)原因胁黑,創(chuàng)建內(nèi)部類(lèi)的實(shí)例時(shí)必須先有外部類(lèi)的實(shí)例废封。

定義一個(gè)非靜態(tài)內(nèi)部類(lèi)

如果內(nèi)部類(lèi)和外部類(lèi)擁有同名成員變量,如果直接使用變量名訪(fǎng)問(wèn)丧蘸,遵循就近原則漂洋,方法的只可能是內(nèi)部類(lèi)自身的成員。但是可以通過(guò) 外部類(lèi).this.變量名 的方式來(lái)明確指明需要調(diào)用的是外部類(lèi)成員而不是內(nèi)部類(lèi)的成員力喷。

例:

class Outter {

    private String name;

    public Outter(String name) {
        this.name = name;
    }

    public class Inner {
        private String name;

        public Inner(String name) {
            this.name = name;
        }

        public String desc() {
            return Outter.this.name + "-" + name;
        }
    }

    public void foo(Inner bar) {
        System.out.println(bar.desc());
    }
}

使用該內(nèi)部類(lèi)

Outter outter1 = new Outter("Outter1");
Outter.Inner inner1 = outter1.new Inner("Inner1");

Outter outter2 = new Outter("Outter2");
Outter.Inner inner2 = outter2.new Inner("Inner2");

System.out.println("outter1 is " + outter1.getClass()); //  _innerclass.Outter
System.out.println("outter2 is " + outter2.getClass()); //  _innerclass.Outter
System.out.println("inner1 is " + inner1.getClass());   //  _innerclass.Outter$Inner
System.out.println("inner2 is " + inner2.getClass());   //  _innerclass.Outter$Inner

outter1.foo(inner1);    //  Outter1-Inner1
outter1.foo(inner2);    //  Outter2-Inner2

以上可以看到 inner1inner2 兩個(gè)通過(guò)不同外部類(lèi)實(shí)例創(chuàng)建的內(nèi)部類(lèi)對(duì)象并沒(méi)有什么區(qū)別刽漂,可見(jiàn)內(nèi)部類(lèi)是屬于外部類(lèi)的。

Groovy 篇

靜態(tài)內(nèi)部類(lèi)

使用同 Java

定義一個(gè)靜態(tài)內(nèi)部類(lèi)

class Outter {
    static class StaticInner {
    }
}

創(chuàng)建靜態(tài)內(nèi)部類(lèi)的實(shí)例

def staticInner = new Outter.StaticInner()

匿名內(nèi)部類(lèi)

匿名內(nèi)部類(lèi)使用也同 Java

例:

def thread = new Thread(new Runnable() {
    @Override
    void run() {

    }
})

非靜態(tài)內(nèi)部類(lèi)

非靜態(tài)內(nèi)部類(lèi)使用也同 Java弟孟。但是爽冕,在 Groovy 中創(chuàng)建內(nèi)部類(lèi)的實(shí)例時(shí)語(yǔ)法與 Java 不同,使用的是 new 外部類(lèi).內(nèi)部類(lèi)(外部類(lèi)的實(shí)例 [, 內(nèi)部類(lèi)的構(gòu)造方法的參數(shù)])披蕉,且此時(shí)指明內(nèi)部類(lèi)的構(gòu)造方法參數(shù)時(shí)不能使用帶名參數(shù)颈畸。

定義一個(gè)非靜態(tài)內(nèi)部類(lèi)

class Outter {

    def name

    static class StaticInner {
    }

    class Inner {
        def name
        Inner(def name) {
            this.name = name
        }
        def desc = "${Outter.this.name}-${name}"
    }

    def foo(Inner bar) {
        println(bar.desc)
    }
}

使用該內(nèi)部類(lèi)

def outter1 = new Outter(name: "Outter1")
//  Wrong!! 不能使用帶名參數(shù)
//        def inner1 = new Outter.Inner(outter1, name: "Inner1")
def inner1 = new Outter.Inner(outter1, "Inner1")

def outter2 = new Outter(name: "Outter2")
def inner2 = new Outter.Inner(outter2, "Inner2")

println("outter1 is ${outter1.getClass()}") //  _innerclass.Outter
println("outter2 is ${outter2.getClass()}") //  _innerclass.Outter
println("inner1 is ${inner1.getClass()}")   //  _innerclass.Outter$Inner
println("inner2 is ${inner2.getClass()}")   //  _innerclass.Outter$Inner

outter1.foo(inner1) //  Outter1-Inner1
outter1.foo(inner2) //  Outter2-Inner2

由以上例子可見(jiàn)在 Groovy 中內(nèi)部類(lèi)也是屬于外部類(lèi)的乌奇。

Scala 篇

匿名內(nèi)部類(lèi)

匿名內(nèi)部類(lèi)使用也同 Java

val thread = new Thread(new Runnable {
  def run(): Unit = {

  }
})

非靜態(tài)內(nèi)部類(lèi)

Scala 中非靜態(tài)內(nèi)部類(lèi)與 Java 中有很大不同。Scala 中非靜態(tài)內(nèi)部類(lèi)是屬于外部類(lèi)的實(shí)例眯娱,而不是外部類(lèi)自身礁苗。

定義一個(gè)非靜態(tài)內(nèi)部類(lèi)

Scala 中內(nèi)部類(lèi)也可以通過(guò) 外部類(lèi).this.成員名 來(lái)訪(fǎng)問(wèn)外部類(lèi)的成員,或者也可以通過(guò)像如下的 outter => 定義一個(gè) 外部類(lèi).this 的別名來(lái)訪(fǎng)問(wèn)徙缴。

class Outter(val name: String) {
  outter =>

  class Inner(val name: String) {
    def desc = s"${Outter.this.name}-$name"

    def desc2 = s"${outter.name}-$name"
  }

  def foo(bar: Inner): Unit = {
    println(bar.desc)
  }
}

使用該內(nèi)部類(lèi)

val outter1 = new Outter("Outter1")
val inner1 = new outter1.Inner("Inner1")

val outter2 = new Outter("Outter2")
val inner2 = new outter2.Inner("Inner2")

println(s"outter1 is ${outter1.getClass}") //  _innerclass.Outter
println(s"outter2 is ${outter2.getClass}") //  _innerclass.Outter
println(s"inner1 is ${inner1.getClass}")  //  _innerclass.Outter$Inner
println(s"inner2 is ${inner2.getClass}")  //  _innerclass.Outter$Inner

以上打印時(shí)可以看到 inner1inner2 的類(lèi)型看起來(lái)是一樣的试伙。但是調(diào)用以下方法后會(huì)發(fā)現(xiàn)報(bào) type mismatch 錯(cuò)誤。

outter1.foo(inner1)
//  Wrong!! type mismatch
//  outter1.foo(inner2)  

實(shí)際上這是由于 Scala 中存在著一種被稱(chēng)作 "路徑依賴(lài)類(lèi)型" 的概念于样,即 "A.this.B" 隨著 A 是不同的實(shí)例而不同疏叨。所以以上定義的 foo() 方法只能接受特定路徑的 Inner 類(lèi)的實(shí)例。

如果希望 foo() 方法接收所有 Outter 實(shí)例路徑下的 Inner 類(lèi)型穿剖,可以使用類(lèi)型投影蚤蔓。類(lèi)型投影使用符號(hào) # 來(lái)定義。

例:

foo() 方法換成以下形式

def foo(bar: Outter#Inner): Unit = {
  println(bar.desc2)
}

再調(diào)用以下方法就不會(huì)報(bào)錯(cuò)了

outter1.foo(inner1)
outter1.foo(inner2)

Kotlin 篇

匿名內(nèi)部類(lèi)

匿名內(nèi)部類(lèi)使用也同 Java

val thread = Thread(Runnable {

})

非靜態(tài)內(nèi)部類(lèi)

Kotlin 中非靜態(tài)內(nèi)部類(lèi)與 Java 相似糊余。

定義一個(gè)非靜態(tài)內(nèi)部類(lèi)

Kotlin 中內(nèi)部類(lèi)使用語(yǔ)法 this@外部類(lèi).成員名 來(lái)調(diào)用外部成員秀又。

class Outter(val name: String) {

    inner class Inner(val name: String) {
        fun desc() = "${this@Outter.name}-${name}"
    }

    fun foo(bar: Inner) {
        println(bar.desc())
    }
}

使用該內(nèi)部類(lèi)

val outter1 = Outter("Outter1")
val inner1 = outter1.Inner("Inner1")

val outter2 = Outter("Outter2")
val inner2 = outter1.Inner("Inner2")

println("outter1 is ${outter1.javaClass}")  //  _innerclass.Outter
println("outter2 is ${outter2.javaClass}")  //  _innerclass.Outter
println("inner1 is ${inner1.javaClass}")    //  _innerclass.Outter$Inner
println("inner2 is ${inner2.javaClass}")    //  _innerclass.Outter$Inner

outter1.foo(inner1) //  Outter1-Inner1
outter1.foo(inner2) //  Outter1-Inner2

Summary

  • Scala 中非靜態(tài)內(nèi)部類(lèi)屬于外部類(lèi)的對(duì)象而非外部類(lèi)本身,而其它三種語(yǔ)言中則屬于外部類(lèi)
  • Scala 中可以定義外部類(lèi)this的別名
  • Scala 與 Kotlin 沒(méi)有靜態(tài)外部類(lèi)
  • Groovy 中內(nèi)部類(lèi)使用方法與 Java 基本一致贬芥,只是創(chuàng)建內(nèi)部類(lèi)語(yǔ)法的方式不一樣
  • Kotlin 使用 this 的語(yǔ)法和其它三種語(yǔ)言都不一樣

文章源碼見(jiàn) https://github.com/SidneyXu/JGSK 倉(cāng)庫(kù)的 _17_innerclass 小節(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吐辙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蘸劈,更是在濱河造成了極大的恐慌昏苏,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件威沫,死亡現(xiàn)場(chǎng)離奇詭異捷雕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)壹甥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)救巷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人句柠,你說(shuō)我怎么就攤上這事浦译。” “怎么了溯职?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵精盅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谜酒,道長(zhǎng)叹俏,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任僻族,我火速辦了婚禮粘驰,結(jié)果婚禮上屡谐,老公的妹妹穿的比我還像新娘。我一直安慰自己蝌数,他們只是感情好愕掏,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著顶伞,像睡著了一般饵撑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上唆貌,一...
    開(kāi)封第一講書(shū)人閱讀 49,792評(píng)論 1 290
  • 那天误阻,我揣著相機(jī)與錄音试读,去河邊找鬼氮兵。 笑死勋颖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蓖租。 我是一名探鬼主播粱侣,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼羊壹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蓖宦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起油猫,我...
    開(kāi)封第一講書(shū)人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤稠茂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后情妖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體睬关,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年毡证,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了电爹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡料睛,死狀恐怖丐箩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恤煞,我是刑警寧澤屎勘,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站居扒,受9級(jí)特大地震影響概漱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喜喂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一瓤摧、第九天 我趴在偏房一處隱蔽的房頂上張望竿裂。 院中可真熱鬧,春花似錦姻灶、人聲如沸铛绰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捂掰。三九已至,卻和暖如春曾沈,著一層夾襖步出監(jiān)牢的瞬間这嚣,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工塞俱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姐帚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓障涯,卻偏偏與公主長(zhǎng)得像罐旗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唯蝶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法九秀,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法粘我,繼承相關(guān)的語(yǔ)法鼓蜒,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,598評(píng)論 18 399
  • 前言 人生苦多征字,快來(lái) Kotlin 都弹,快速學(xué)習(xí)Kotlin匙姜! 什么是Kotlin畅厢? Kotlin 是種靜態(tài)類(lèi)型編程...
    任半生囂狂閱讀 26,166評(píng)論 9 118
  • Java 內(nèi)部類(lèi) 分四種:成員內(nèi)部類(lèi)、局部?jī)?nèi)部類(lèi)氮昧、靜態(tài)內(nèi)部類(lèi)和匿名內(nèi)部類(lèi)框杜。 1、成員內(nèi)部類(lèi): 即作為外部類(lèi)的一個(gè)成...
    ikaroskun閱讀 1,223評(píng)論 0 13
  • 一:java概述:1郭计,JDK:Java Development Kit霸琴,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工...
    ZaneInTheSun閱讀 2,635評(píng)論 0 11
  • 從前覺(jué)得18歲很遠(yuǎn)选调,一轉(zhuǎn)眼已過(guò)5年了夹供! 去年的生日,在杭州姐姐給過(guò)了一次仁堪,在無(wú)錫哥哥給過(guò)了一次哮洽,在家父母給過(guò)了一次...
    婚禮主持人諾言閱讀 488評(píng)論 0 0