• 成员内部类详解


    成员内部类

    作为外部类的一个成员存在的类称为成员内部类。


    注意:

    必须先创建外部类才能创建内部类。

    成员内部类不能含有static的变量和方法。因为成员内部类需要先创建外部类,才能创建它自己的。 


    代码:

    public class Outer {
        private String s1 = "this is s1 in Outer";
        private String s2 = "this is s2 in Outer";
    
        public void method1() {
            // 外部类可通过内部类的对象调用内部类的私有成员变量或方法
            System.out.println(new Inner().s1);
            System.out.println(new Inner().method2());
        }
    
        private String method2() {
            return "this is method2 in Outer";
        }
    
        public class Inner {
            private String s1 = "this is s1 in Inner";
            public final static String s2 = "this is s2 in Inner";
    
            public void method1() {
                // 内部类可直接使用外部类的私有成员变量或方法
                System.out.println(s2);
                // 内部类和外部类有同名变量和方法时
                System.out.println(s1);
                System.out.println(Outer.this.s1);
                System.out.println(method2());
                System.out.println(Outer.this.method2());
            }
    
            private String method2() {
                return "this is method2 in Inner";
            }
        }
    }

    调用:

    public class MainClass {
        public static void main(String[] args) {
            Outer outer = new Outer();
            System.out.println("------外部类测试--------");
            outer.method1();
            System.out.println("------内部类测试--------");
            outer.new Inner().method1();
            System.out.println(Outer.Inner.s2);
        }
    }

    打印:

    ------外部类测试--------
    this is s1 in Inner
    this is method2 in Inner
    ------内部类测试--------
    this is s2 in Inner
    this is s1 in Inner
    this is s1 in Outer
    this is method2 in Inner
    this is method2 in Outer
    this is s2 in Inner

    分析:

    反编译后自动生成文件:Outer$Inner.class

    Outer 反编译代码1:

    public class jichu.Outer {
      private java.lang.String s1;
      private java.lang.String s2;
      public jichu.Outer();
      public void method1();
      private java.lang.String method2();
      static java.lang.String access$0(jichu.Outer);
      static java.lang.String access$1(jichu.Outer);
      static java.lang.String access$2(jichu.Outer);
    }

    Outer 反编译代码2:

    public class Outer
    {
      private String s1 = "this is s1 in Outer";
      private String s2 = "this is s2 in Outer";
      
      public void method1()
      {
        System.out.println(new Inner().s1);
        System.out.println(new Inner().method2());
      }
      
      private String method2()
      {
        return "this is method2 in Outer";
      }
      
      public class Inner
      {
        private String s1 = "this is s1 in Inner";
        public static final String s2 = "this is s2 in Inner";
        
        public Inner() {}
        
        public void method1()
        {
          System.out.println("this is s2 in Inner");
          
          System.out.println(this.s1);
          System.out.println(Outer.this.s1);
          System.out.println(method2());
          System.out.println(Outer.this.method2());
        }
        
        private String method2()
        {
          return "this is method2 in Inner";
        }
      }
    }

    Outer$Inner反编译代码1:

    public class jichu.Outer$Inner {
      private java.lang.String s1;
      public static final java.lang.String s2;
      final jichu.Outer this$0;
      public jichu.Outer$Inner(jichu.Outer);
      public void method1();
      private java.lang.String method2();
      static java.lang.String access$0(jichu.Outer$Inner);
      static java.lang.String access$1(jichu.Outer$Inner);
    }

    Outer$Inner反编译代码2:

    public class Outer$Inner
    {
      private String s1 = "this is s1 in Inner";
      public static final String s2 = "this is s2 in Inner";
      
      public Outer$Inner(Outer paramOuter) {}
      
      public void method1()
      {
        System.out.println("this is s2 in Inner");
        
        System.out.println(this.s1);
        System.out.println(Outer.access$0(this.this$0));
        System.out.println(method2());
        System.out.println(Outer.access$1(this.this$0));
      }
      
      private String method2()
      {
        return "this is method2 in Inner";
      }
    }

    MainClass反编译代码:

    public class MainClass
    {
      public static void main(String[] args)
      {
        Outer outer = new Outer();
        System.out.println("------外部类测试--------");
        outer.method1();
        System.out.println("------内部类测试--------");
    Outer tmp33_32
    = outer;
    tmp33_32.getClass();
    new Outer.Inner(tmp33_32).method1();
    System.out.println("this is s2 in Inner"); } }

    MainClass中有代码:

    Outer tmp33_32 = outer;
    new Outer.Inner(tmp33_32).method1();

    可以看出生成Inner对象时,将tmp33_32(即外部类对象outer的引用)传入Inner的构造器中,这个构造器从哪来的?

    Outer$Inner中有代码:

    public jichu.Outer$Inner(jichu.Outer);

    这是编译器自动生成的构造器,参数为外部类对象,通过将tmp33_32传入构造器,来建立外部类与内部类的联系。

    Outer$Inner中有代码:

     final jichu.Outer this$0;

    猜测Outer$Inner通过构造器将外部类对象的引用赋予变量this$0;

    当内部类调用外部类的私有变量和方法时,

    Outer$Inner中有代码:

    System.out.println(Outer.access$0(this.this$0));
    System.out.println(Outer.access$1(this.this$0));
    System.out.println(Outer.access$2(this.this$0));

    Outer中有代码:

    static java.lang.String access$0(jichu.Outer);
    static java.lang.String access$1(jichu.Outer);
    static java.lang.String access$2(jichu.Outer);

    access$i是JAVA编译器自动生成的十分重要的方法(该方法的个数与内部类要访问的外部类的变量个数相关),目的是:用于内部类访问外部类的数据成员时使用。

    在内部类中通过Outer.access$i(this.this$0)的方式,可实现对外部类的私有变量和方法的随意访问。


    疑问

    成员内部类不能含有static的变量和方法。但是测试发现变量可以被static final修饰,为什么?

    主要是因为final类型在编译期间jvm有优化,常量池会维护这些变量。虽然非静态内部类不能脱离外部类这个上下文实例化,但是常量池使得final变量脱离了类实例化这个条件,编译期间便可确定。

    Outer$Inner中有代码:

    public static final String s2 = "this is s2 in Inner";

    MainClass中有代码:

     System.out.println(Outer.Inner.s2);

    通过Outer.Inner.s2来访问static final的变量;

    MainClass反编译代码中有:

     System.out.println("this is s2 in Inner");

    s2在编译时被"this is s2 in Inner"直接替换。 


    总结:

    1、内部类可直接使用外部类的私有成员变量或方法,外部类对内部类是可见的;

    2、外部类中可以创建私有内部类对象。

    3、外部类可通过内部类的对象调用内部类的私有成员变量或方法;

    4、当内部类与外部类有同名成员变量和方法时,内部类可通过Outer.this方式来引用外部类成员。

    5、必须先创建外部类才能创建内部类。

    6、成员内部类不能含有static的变量和方法。因为成员内部类需要先创建外部类,才能创建它自己的。 

  • 相关阅读:
    奇怪的肚疼
    惊喜:vs2005 和 msdn 中文版 已经提供Subscriber 下载,MSDN全球订户可以下中文版爽了
    英语构语法(前、后缀部分)
    TSQL中的递归 作者:Alexander Kozak
    筹划向 Visual Studio 2005 导航控件的迁移 作者:Dave Donaldson Steven DeWalt
    Atlas客服端文件介绍
    Chinese lunar calendar for www.live.com
    帮助解决网页和JS文件中的中文编码问题的小工具
    ADO.NET 2.0 功能一览 作者:Bob Beauchemin
    Prototype.js 1.4中文使用手册PDF版下载
  • 原文地址:https://www.cnblogs.com/SQP51312/p/6101688.html
Copyright © 2020-2023  润新知