《Thinking In Java》內(nèi)部類

《Thinking In Java》內(nèi)部類

定義:可以將一個(gè)類的定義放在另一個(gè)類的內(nèi)部腻惠,這就是內(nèi)部類。

創(chuàng)建內(nèi)部類

public class OuterTest1 {
private String name = "王天逾";
//創(chuàng)建內(nèi)部類
class InnerClass1{
int i;
InnerClass1(int i){
this.i = i;
}
public void f1(){
System.out.println("姓名:"+name+" 年齡:"+this.i);
}
}
public InnerClass1 getInnerClass1(){
return  new InnerClass1(22);
}

public static void main(String[] args) {
OuterTest1 outerTest1 = new OuterTest1();
outerTest1.getInnerClass1().f1();
}
}

打印結(jié)果:

姓名:王天逾 年齡:22

外部類有一個(gè)方法getInnerClass1()返回一個(gè)內(nèi)部類的引用乙各。在內(nèi)部類有個(gè)普通方法f1(),它可以訪問(wèn)外部類變量name,即使它在外圍類中是private修飾符爬骤。也就是說(shuō),當(dāng)生成一個(gè)內(nèi)部類對(duì)象時(shí)贱纠,此對(duì)象與制造它的外圍類對(duì)象直接就有了聯(lián)系峻厚,它能夠訪問(wèn)外圍類對(duì)象的所有成員,內(nèi)部類還擁有其外圍類的所有的訪問(wèn)權(quán)谆焊。

.this 和 .new用法

  • .this用法介紹

如果你想在內(nèi)部類中返回外部類對(duì)象的引用惠桃,可以使用外部類的名字.this

public class OuterTest1 {
public void f1(){
System.out.println(".this用法。辖试。辜王。");
}
class InnerClass{
public OuterTest1 getOuterObject(){
return  OuterTest1.this;
}
}
public InnerClass getInnerInstance(){
return  new InnerClass();
}
public static void main(String[] args) {
 OuterTest1 outerTest1 = new OuterTest1();
 outerTest1.getInnerInstance().getOuterObject().f1();
}
}
  • .new用法介紹

有時(shí)候你想要告知某些其他對(duì)象去創(chuàng)建其某個(gè)內(nèi)部類對(duì)象,要實(shí)現(xiàn)這個(gè)目的罐孝,就必須在new表達(dá)式中提供對(duì)其外部類對(duì)象的引用呐馆,這就需要.new用法

此時(shí)刪掉getInnerInstance()方法,在main()中創(chuàng)建內(nèi)部類對(duì)象莲兢,看一下代碼

public class OuterTest1 {
public void f1(){
    System.out.println(".new用法汹来。。改艇。");
}
class InnerClass{
public OuterTest1 getOuterObject(){
     return  OuterTest1.this;
  }
}

public static void main(String[] args) {
 OuterTest1 outerTest= new OuterTest1();
 outerTest.new InnerClass().getOuterObject().f1();
  }
}

<font color=#f00 size=3>注意:
這里必須使用外部類的對(duì)象來(lái)創(chuàng)建該內(nèi)部類對(duì)象收班,之所以這么做,是因?yàn)閮?nèi)部類對(duì)象會(huì)默認(rèn)連接到外部類對(duì)象中遣耍。但是闺阱,如果創(chuàng)建的是靜態(tài)內(nèi)部類,那么它就不需要對(duì)外部類對(duì)象的引用了舵变。</font>

對(duì)于后半句酣溃,來(lái)寫(xiě)一下瘦穆。是可以編譯運(yùn)行的。

 public class OuterTest1 {
   static class InnerClass{
public void getSomething(){
   System.out.println("這是靜態(tài)內(nèi)部類赊豌。扛或。。");
   }
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.getSomething();
   }
}

內(nèi)部類與向上轉(zhuǎn)型

public class OuterTest2 {
private class DestinationImpl implements Destination {
String s;

DestinationImpl(String s) {
this.s = s;
}

@Override
public void readDestination() {
System.out.println(s);
}
}

protected class ContentsImpl implements Contents {

@Override
public int value() {
return 1;
}
}

public Destination getDestination() {
return new DestinationImpl("崇明島");
}

public Contents getContents() {
return new ContentsImpl();
}

public static void main(String[] args) {
OuterTest2 outerTest2 = new OuterTest2();
outerTest2.getDestination().readDestination();
outerTest2.getContents().value();
}
}

內(nèi)部類實(shí)現(xiàn)了接口碘饼,得到了對(duì)此接口的引用熙兔,與向上轉(zhuǎn)型為這個(gè)對(duì)象的基類,是一樣的艾恼。

在方法的內(nèi)部類(局部?jī)?nèi)部類)

public class OuterTest3 {
public Destination getDestination(){
 class MyDestinationImpl implements  Destination{

 @Override
 public void readDestination() {
      System.out.println("111");
   }
 }
 return new MyDestinationImpl();
}

public static void main(String[] args) {
    OuterTest3 outerTest3  = new OuterTest3();
    outerTest3.getDestination().readDestination();
  }
}

MyDestinationImpl類是getDestination()的一部分住涉,而不是OuterTest3的一部分。所以钠绍,在getDestination()之外是無(wú)法訪問(wèn)MyDestinationImpl的舆声。return的時(shí)候使用了向上轉(zhuǎn)型,因?yàn)镈estination是MyDestinationImpl的基類柳爽。

在特定的作用域內(nèi)的內(nèi)部類

public class OuterTest3 {
 private void f1(boolean b){
 if(b){
      class MyClass {
      void f2(){
      System.out.println("5201314");
      }
 }
 MyClass myClass = new MyClass();
 myClass.f2();
    }
 }

public static void main(String[] args) {
   OuterTest3 outerTest3 = new OuterTest3();
   outerTest3.f1(true);
   }
}

MyClass是被嵌入在if語(yǔ)句的作用域內(nèi)媳握,在定義MyClass類之外的作用域是不可用的,除此之外磷脯,它與普通類沒(méi)區(qū)別蛾找。

匿名內(nèi)部類

public class OuterTest3 {
public Contents getContents() {
return new Contents() {
  @Override
  public int value() {
      return 520;
   }
  };
}

public static void main(String[] args) {
   OuterTest3 outerTest3 = new OuterTest3();
   System.out.println(outerTest3.getContents().value());
   }
}

匿名內(nèi)部類:創(chuàng)建一個(gè)繼承自父類的匿名內(nèi)對(duì)象,通過(guò)new表達(dá)式返回的引用被自動(dòng)向上轉(zhuǎn)型為對(duì)父類(這里是Contents)的引用赵誓。

將上面匿名內(nèi)部類改成正常形式打毛。

public class OuterTest3 {

public Contents getContents() {
    return new ContentsImpl();
}

class ContentsImpl implements Contents {
    @Override
    public int value() {
        return 520;
    }
}

public static void main(String[] args) {
    OuterTest3 outerTest3 = new OuterTest3();
    System.out.println(outerTest3.getContents().value());
  }
}

在這里父類Contents不需要接收參數(shù),使用了默認(rèn)構(gòu)造架曹,那么隘冲,想要為父類傳遞參數(shù)呢闹瞧?

class Fu {
int i;
Fu(int i) {
this.i = i;
}

public int f() {
return this.i;
  }
}

public class OuterTest3 {
public Fu getFuObject(int i) {
return new Fu(i) {
@Override
public int f() {
return super.f() * 100;
   }
  };
}

public static void main(String[] args) {
OuterTest3 outerTest3 = new OuterTest3();
System.out.println(outerTest3.getFuObject(2).f()); 
   }
}

只需簡(jiǎn)單的傳遞合適的參數(shù)給基類的構(gòu)造器就好了绑雄。

在匿名內(nèi)部類中定義字段時(shí),還能夠?qū)ζ溥M(jìn)行初始化操作

public class OuterTest3 {
public Contents getContents(final int i) {
  return new Contents() {
    int ii=i;
    @Override
    public int value() {
    return ii;
    }
 };
}

public static void main(String[] args) {
  OuterTest3 outerTest3 = new OuterTest3();
  System.out.println(outerTest3.getContents(100).value());
  }
}

如果定義一個(gè)匿名內(nèi)部類奥邮,并且希望其使用外部定義的對(duì)象万牺,那么參數(shù)引用必須是final類型。

為匿名內(nèi)部類創(chuàng)建"構(gòu)造器效果"

匿名內(nèi)部類不可能有命名構(gòu)造器(因?yàn)樗鼪](méi)有名字)洽腺,但可以通過(guò)實(shí)例初始化脚粟,就能夠達(dá)到為匿名內(nèi)部類創(chuàng)建構(gòu)造器效果。

abstract  class BaseClass{

public abstract  void f();
BaseClass(int i){
System.out.println(i);
}
}

public class OuterTest3 {
 static  class  MyBase {
 public BaseClass getBaseClass(int i){
 return  new BaseClass(i) {
 {
 System.out.println("inside");
 }
 @Override
 public void f() {
 System.out.println("anonymous");
 }
 };
 }
 }

public static void main(String[] args) {
  MyBase myBase = new MyBase();
  myBase.getBaseClass(10).f();

}
}

打印結(jié)果:

10
inside
anonymous

這里沒(méi)有為參數(shù)設(shè)置final int i,是因?yàn)槟涿麅?nèi)部類中沒(méi)有使用i,只是傳遞給了父類構(gòu)造蘸朋。

嵌套類

定義:如果不需要內(nèi)部類對(duì)象與其外圍類對(duì)象之間有關(guān)系核无,那么可以將內(nèi)部類聲明為static

普通內(nèi)部類對(duì)象隱式地保存了一個(gè)引用,指向創(chuàng)建他的外圍類對(duì)象藕坯,然而团南,當(dāng)內(nèi)部類為static時(shí)噪沙,就不是這樣了。

<font color=#f00 size=3>

  • 要?jiǎng)?chuàng)建嵌套類對(duì)象吐根,并不需要其外圍類的對(duì)象
  • 不能從嵌套類的對(duì)象中訪問(wèn)非靜態(tài)的外圍類對(duì)象

</font>

普通內(nèi)部類不能包含static數(shù)據(jù)和字段正歼,而靜態(tài)內(nèi)部類則可以

 public class OuterTest3 {
 private static  class MyContentImpl implements  Contents{
     private static int i=1;
     @Override
     public int value() {
         return 100+i;
     }
 }
 public static   Contents getContents(){
     return new MyContentImpl();

 }
 public static void main(String[] args) {
     Contents contents = getContents();
     System.out.println(contents.value());

 }
}

在main()中,根本就沒(méi)有生成外部類對(duì)象拷橘,而是使用static成員的普通語(yǔ)法來(lái)調(diào)用一個(gè)返回對(duì)Contents接口的引用局义。

接口內(nèi)部的類

通常情況下,接口內(nèi)部不能放置任何代碼冗疮,但嵌套類可以萄唇,在接口里面,默認(rèn)類是public static术幔,由于是static穷绵,只是將嵌套類置于接口的命名空間內(nèi),這并不違反接口的規(guī)則特愿。

interface ClassInterfaces {

void f();

class OuterTest3 implements ClassInterfaces {

    @Override
    public void f() {
        System.out.println("接口內(nèi)部類測(cè)試仲墨。。揍障。");
    }


    public static void main(String[] args) {
        new OuterTest3().f();
    }
}
}
從多層嵌套類中訪問(wèn)外部類成員

一個(gè)內(nèi)部類被嵌套多少層并不重要目养,它總能訪問(wèn)外部類的所有成員

public class MNA {
private void f1() {
    System.out.println("f1");
}

class A {
    private void f2() {
        System.out.println("f2");
    }

    public class B {
        private void f3() {
            f1();
            f2();
        }

    }
}

public static void main(String[] args) {
    MNA mna = new MNA();
    A a = mna.new A();
    A.B b = a.new B();
    b.f3();
}
}

內(nèi)部類的繼承

內(nèi)部類的構(gòu)造器必須連接到外圍類的對(duì)象的引用,所以毒嫡,那個(gè)指向外圍類對(duì)象的引用必須被初始化癌蚁,而導(dǎo)出類中在不再存在可連接的默認(rèn)對(duì)象,要解決這個(gè)問(wèn)題兜畸,需要使用enclosingClassReference.super();

class WithInner {
class Inner {
  public void f() {
    System.out.println("hh");
  }
 }

}

public class InheritInner extends WithInner.Inner {
   InheritInner(WithInner i) {
   i.super();
}

public static void main(String[] args) {
  WithInner wi = new WithInner();
  InheritInner inheritInner = new InheritInner(wi);
  inheritInner.f();
 }
}

通過(guò)i.super()努释,提供了必要的引用,然后程序編譯通過(guò)咬摇。

內(nèi)部類標(biāo)識(shí)符

  • 每個(gè)類都會(huì)產(chǎn)生一個(gè).class文件伐蒂,內(nèi)部類也不例外.

  • 外部類的名字+"$"+內(nèi)部類的名字

  • 如果是匿名內(nèi)部類,編譯器會(huì)簡(jiǎn)單的產(chǎn)生一個(gè)數(shù)字作為其標(biāo)識(shí)符肛鹏。

  • 如果內(nèi)部類嵌套在別的內(nèi)部類中逸邦,只需將他們的名字加在外圍類標(biāo)識(shí)符與$的后面

聲明

這篇博文是《Thinking in Java》內(nèi)部類讀書(shū)筆記。還有幾個(gè)內(nèi)部類知識(shí)點(diǎn)沒(méi)有搞明白在扰,這里沒(méi)做筆記缕减,等下次充分理解后,再補(bǔ)充芒珠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末桥狡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌裹芝,老刑警劉巖呈宇,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異局雄,居然都是意外死亡甥啄,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)炬搭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蜈漓,“玉大人,你說(shuō)我怎么就攤上這事宫盔∪谒洌” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵灼芭,是天一觀的道長(zhǎng)有额。 經(jīng)常有香客問(wèn)我,道長(zhǎng)彼绷,這世上最難降的妖魔是什么巍佑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮寄悯,結(jié)果婚禮上萤衰,老公的妹妹穿的比我還像新娘。我一直安慰自己猜旬,他們只是感情好脆栋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著洒擦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熟嫩。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天洋侨,我揣著相機(jī)與錄音,去河邊找鬼倦蚪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛边苹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慕购,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼聊疲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了沪悲?” 一聲冷哼從身側(cè)響起获洲,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤殿如,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后涉馁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寒随,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年帮坚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片试和。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灰署,死狀恐怖判帮,靈堂內(nèi)的尸體忽然破棺而出溉箕,到底是詐尸還是另有隱情,我是刑警寧澤晌畅,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布寡痰,位于F島的核電站,受9級(jí)特大地震影響拦坠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜入热,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绰播,春花似錦尚困、人聲如沸蠢箩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)呵萨。三九已至跨跨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忱嘹,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工拘悦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橱脸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓屁桑,卻偏偏與公主長(zhǎng)得像栏赴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子须眷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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

  • 今天整理一下內(nèi)部類花颗,其中包含了內(nèi)部類的特殊形式,對(duì)比普通類有什么區(qū)別和作用捎稚,內(nèi)部類和外圍類之間的聯(lián)系求橄,內(nèi)部類的擴(kuò)展...
    _小二_閱讀 608評(píng)論 0 3
  • 可以將一個(gè)類的定義放到另一個(gè)類的定義內(nèi)部,這就是內(nèi)部類条霜。 10.1 創(chuàng)建內(nèi)部類 如果想從外部類的非靜態(tài)方法之外的任...
    張利強(qiáng)閱讀 1,022評(píng)論 0 2
  • 內(nèi)部類是一種非常有用的特性,因?yàn)樗试S你把一些邏輯相關(guān)的類組織在一起蒲凶,并控制位于內(nèi)部的類的可視性拆内。 如果想從外部類...
    Lemon_Home閱讀 219評(píng)論 0 0
  • 今天早上聽(tīng)了麥樂(lè)老師的一場(chǎng)分享,說(shuō)到每個(gè)人都有小我刻肄、高我和大腦。只有去和高我連結(jié)才能讓小我擺脫大腦的錯(cuò)覺(jué)敏弃,活出真...
    杏子心語(yǔ)閱讀 920評(píng)論 0 0
  • 有人說(shuō):人啊步清,過(guò)了二十幾歲,上帝就會(huì)開(kāi)始給你做減法廓啊。拿掉你的一些朋友封豪,拿掉你的一些夢(mèng)想。有些人跟你分道揚(yáng)鑣...
    19畫(huà)生閱讀 8,295評(píng)論 0 2