java內(nèi)部類


/**
 * @author wangcheng
 * @date 17/12/20
 */
public class Outer {

    /*
        Outer外部類的反編譯結(jié)果,可以發(fā)現(xiàn)對于私有變量data的訪問實際上是通過access$000()方法進(jìn)行的
        public class com.thinkjoy.InnerClass.Outer {
          public com.thinkjoy.InnerClass.Outer();
          public void local(java.lang.String, java.lang.String);
          public static void main(java.lang.String[]);
          static int access$000(com.thinkjoy.InnerClass.Outer);
        }

        static int access$100(com.thinkjoy.InnerClass.Outer);
            Code:
               0: aload_0
               1: getfield      #1                  // Field data:I
               4: ireturn

        aload_0: 對static方法來說獲取第一個參數(shù),對非static方法來說是this
        getfield: 獲取Outer的data字段
        ireturn: 返回int類型
     */

    // 為什么內(nèi)部類可以訪問外部類的私有變量?
    // 首先,在編譯后,該內(nèi)部類和外部類是兩個獨立的文件Outer.class和Outer$MemberInner.class
    // 那么,兩個獨立類怎么可以訪問到自己的成員變量,
    // 一種方式是直接在類內(nèi)部--這種顯然是不對的,因為已經(jīng)編譯成兩個類文件了
    // 第二種方式是通過該類的對象訪問,但是對象只能訪問可見的成員變量,如protected修飾的變量,只能在同包和子類中通過對象直接訪問,
    // 那么怎么訪問private呢?
    // 通過查看反編譯文件,得知Outer.class中多出了access$000(Outer)這么一個靜態(tài)方法,這個方法返回值就是data
    // 如步驟③,內(nèi)部類直接可以訪問外部類的data,實際執(zhí)行的語句是這樣的 System.out.println(Outer.access$000(this$0));
    //
    // 對于access$000方法不考慮傳入的外部類實例是否可以在其他類中獲取該實例的私有成員變量
    // 訪問修飾符是代碼層面的可見性控制,而access$000是編譯器直接生成的字節(jié)碼,故可以訪問

    private int data = 0;

    static String str = "www";

    //成員內(nèi)部類,訪問修飾符可以是private,protected,default,public
     class MemberInner {
        //static int i = 0; 不能有static局部變量,因為成員內(nèi)部類要在外部類實例創(chuàng)建之后才能創(chuàng)建,當(dāng)內(nèi)部類為講臺局部內(nèi)部類的時候是可以的

        private int count = 0;
        /*
            class com.thinkjoy.InnerClass.Outer$MemberInner {
              final com.thinkjoy.InnerClass.Outer this$0;
              com.thinkjoy.InnerClass.Outer$MemberInner(com.thinkjoy.InnerClass.Outer);
              void print();
              static int access$000(com.thinkjoy.InnerClass.Outer$MemberInner);
                 Code:
                   0: aload_0
                   1: getfield      #1                  // Field count:I
                   4: ireturn
            }
         */

        /*
             Outer.MemberInner memberInner = new Outer().new MemberInner() {
                //nothing to do
             };
             memberInner.print();
             當(dāng)在其他類中進(jìn)行執(zhí)行上述代碼,不會輸出任何東西,
         */

        void print() {
            //③可以訪問外部類的私有變量
            System.out.println(data);
            System.out.println(str);
        }


        class InnerMemberInner{
            /*
                class com.thinkjoy.InnerClass.Outer$MemberInner$InnerMemberInner {
                  final com.thinkjoy.InnerClass.Outer$MemberInner this$1;
                  com.thinkjoy.InnerClass.Outer$MemberInner$InnerMemberInner(com.thinkjoy.InnerClass.Outer$MemberInner);
                  void innerPrint();
                       Code:
                           0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
                           3: aload_0
                           4: getfield      #1                  // Field this$1:Lcom/thinkjoy/InnerClass/Outer$MemberInner;
                           7: invokestatic  #4                  // Method com/thinkjoy/InnerClass/Outer$MemberInner.access$000:(Lcom/thinkjoy/InnerClass/Outer$MemberInner;)I
                          10: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
                          13: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
                          16: aload_0
                          17: getfield      #1                  // Field this$1:Lcom/thinkjoy/InnerClass/Outer$MemberInner;
                          20: getfield      #6                  // Field com/thinkjoy/InnerClass/Outer$MemberInner.this$0:Lcom/thinkjoy/InnerClass/Outer;
                          23: invokestatic  #7                  // Method com/thinkjoy/InnerClass/Outer.access$100:(Lcom/thinkjoy/InnerClass/Outer;)I
                          26: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
                          29: return
                }
            */

            void innerPrint(){
                System.out.println(count);
                System.out.println(data);
            }
        }
    }

    //局部內(nèi)部類,不允許有修飾符,類似局部變量
    public void local(final String name, String age) {


        //①定義在代碼塊中,只能在代碼塊中訪問
        //{
        //  class LocalInner1 {
        //
        //  }
        //}

        //②編譯報錯,找不到該類的符號
        //new LocalInner(){
        //
        //};

        //定義在方法中,可以在方法中訪問,且實例化的代碼必須在定義之后,否則無法訪問,同②
        class LocalInner {
            /*
             該局部內(nèi)部類的
             class com.thinkjoy.InnerClass.Outer$1LocalInner {
                final java.lang.String val$name;
                final com.thinkjoy.InnerClass.Outer this$0;
                com.thinkjoy.InnerClass.Outer$1(com.thinkjoy.InnerClass.Outer, java.lang.String);
                public void print();
             }
             */

            public void print() {
                // name是外部類local方法的參數(shù),且name必須為final,
                // 為什么需要是final?
                // 可以發(fā)現(xiàn),上面的注釋是該局部內(nèi)部類的反編譯代碼,
                // 發(fā)現(xiàn)編譯器將該類重新生成一個單獨的Outer$1LocalInner類,與Outer同包,
                // 在該類中,編譯器新增了一個final的成員變量val$name,也就是Outer的local參數(shù)name的備份,
                // 假如local的name不是final的,也就是name是可以更改的,那么是不是局部內(nèi)部類中的val$name也需要做修改
                // 所以,編譯器規(guī)定,local的name是final的,不可修改,val$name也就是final(因為name不會變了)
                System.out.println(name);
            }
        }

        //匿名內(nèi)部類,沒有名字的內(nèi)部類,其實是繼承Outer$1LocalInner類,編譯器生成的默認(rèn)名字是Outer$1
        LocalInner localInner = new LocalInner() {

            /*
             該匿名內(nèi)部類的
             class com.thinkjoy.InnerClass.Outer$1 extends com.thinkjoy.InnerClass.Outer$1LocalInner {
                final java.lang.String val$name;
                final com.thinkjoy.InnerClass.Outer this$0;
                //包可見的構(gòu)造方法,可以設(shè)置外部類的引用this$0與外部類local方法參數(shù)name的備份
                com.thinkjoy.InnerClass.Outer$1(com.thinkjoy.InnerClass.Outer, java.lang.String);
                public void print();
             }
             */

            @Override
            public void print() {
                //name是外部類local方法的參數(shù),且name必須為final
                System.out.println(name);
                System.out.println(data);
            }
        };

        localInner.print();

    }


    //嵌套內(nèi)部類--staic修飾的內(nèi)部類
    static class StaticInner {
        //可以有靜態(tài)的成員變量,并且可以有修飾符
        private static int data = 0;
    }

    public static void main(String[] args) {

        // ①成員內(nèi)部類的修飾符為private,在當(dāng)前類中是可以訪問內(nèi)部類的,但是在其他類中是不能訪問內(nèi)部類的
        // 同理,其他訪問修飾符是跟成員變量的修飾符的作用是一樣的
        MemberInner memberInner = new Outer().new MemberInner();

        //②嵌套內(nèi)部類
       // System.out.println(StaticInner.data);//可以直接訪問,并且可以根據(jù)修飾符調(diào)整可見性

    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末稀余,一起剝皮案震驚了整個濱河市菇夸,隨后出現(xiàn)的幾起案子串慰,更是在濱河造成了極大的恐慌巢钓,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屿储,死亡現(xiàn)場離奇詭異痘括,居然都是意外死亡萎羔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門医吊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钱慢,“玉大人,你說我怎么就攤上這事卿堂√沧郑” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵御吞,是天一觀的道長麦箍。 經(jīng)常有香客問我,道長陶珠,這世上最難降的妖魔是什么挟裂? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮揍诽,結(jié)果婚禮上诀蓉,老公的妹妹穿的比我還像新娘栗竖。我一直安慰自己,他們只是感情好渠啤,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布狐肢。 她就那樣靜靜地躺著,像睡著了一般沥曹。 火紅的嫁衣襯著肌膚如雪份名。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天妓美,我揣著相機與錄音僵腺,去河邊找鬼。 笑死壶栋,一個胖子當(dāng)著我的面吹牛辰如,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贵试,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼琉兜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毙玻?” 一聲冷哼從身側(cè)響起呕童,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎淆珊,沒想到半個月后夺饲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡施符,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年往声,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戳吝。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡浩销,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出听哭,到底是詐尸還是另有隱情慢洋,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布陆盘,位于F島的核電站普筹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏隘马。R本人自食惡果不足惜太防,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酸员。 院中可真熱鬧蜒车,春花似錦讳嘱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嬉挡,卻和暖如春钝鸽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棘伴。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工寞埠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留屁置,地道東北人焊夸。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像蓝角,于是被迫代替她去往敵國和親阱穗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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