java內(nèi)部類


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

    /*
        Outer外部類的反編譯結(jié)果,可以發(fā)現(xiàn)對(duì)于私有變量data的訪問(wèn)實(shí)際上是通過(guò)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: 對(duì)static方法來(lái)說(shuō)獲取第一個(gè)參數(shù),對(duì)非static方法來(lái)說(shuō)是this
        getfield: 獲取Outer的data字段
        ireturn: 返回int類型
     */

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

    private int data = 0;

    static String str = "www";

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

        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í)行上述代碼,不會(huì)輸出任何東西,
         */

        void print() {
            //③可以訪問(wèn)外部類的私有變量
            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);
            }
        }
    }

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


        //①定義在代碼塊中,只能在代碼塊中訪問(wèn)
        //{
        //  class LocalInner1 {
        //
        //  }
        //}

        //②編譯報(bào)錯(cuò),找不到該類的符號(hào)
        //new LocalInner(){
        //
        //};

        //定義在方法中,可以在方法中訪問(wèn),且實(shí)例化的代碼必須在定義之后,否則無(wú)法訪問(wèn),同②
        class LocalInner {
            /*
             該局部?jī)?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),上面的注釋是該局部?jī)?nèi)部類的反編譯代碼,
                // 發(fā)現(xiàn)編譯器將該類重新生成一個(gè)單獨(dú)的Outer$1LocalInner類,與Outer同包,
                // 在該類中,編譯器新增了一個(gè)final的成員變量val$name,也就是Outer的local參數(shù)name的備份,
                // 假如local的name不是final的,也就是name是可以更改的,那么是不是局部?jī)?nèi)部類中的val$name也需要做修改
                // 所以,編譯器規(guī)定,local的name是final的,不可修改,val$name也就是final(因?yàn)閚ame不會(huì)變了)
                System.out.println(name);
            }
        }

        //匿名內(nèi)部類,沒(méi)有名字的內(nèi)部類,其實(shí)是繼承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;
                //包可見(jiàn)的構(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)前類中是可以訪問(wèn)內(nèi)部類的,但是在其他類中是不能訪問(wèn)內(nèi)部類的
        // 同理,其他訪問(wèn)修飾符是跟成員變量的修飾符的作用是一樣的
        MemberInner memberInner = new Outer().new MemberInner();

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

    }
}
?著作權(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)容

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