当前位置 博文首页 > 文章内容

    为什么内部类可以访问外部类的私有属性?

    作者: 栏目:未分类 时间:2020-10-24 18:00:51

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    使用工具:

    Java 8

    IDEA 2018

     

    1. 内部类的设计原因

      ①内部类方法可以访问外部类的属性,包括私有属性(将内部类定义成单独的外部类,则需要提供访问域的public方法)

           ②内部类可以对同一个包中的其他类隐藏起来(内部类可以是外部类私有的,而外部类的权限只可以是包、public)

           ③当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类比较便捷。

    注意:内部类可以访问外部类的属性,而外部类不能访问内部类的属性。

    举个例子:

    public class OuterAndInnerClass
    {
        private int number;
    
        public static void main(String[] args)
        {
            OuterAndInnerClass outer = new OuterAndInnerClass();
            InnerClass inner = outer.new InnerClass();
            inner.getOuterField();
        }
    
        class InnerClass{
            private String name;
            public void getOuterField(){
                System.out.println("inner class: " + number);   // inner class: 0
            }
        }
    }

    内部类调用外部类的private属性,是可以的。这个内部类inner对象是属于外部类outer对象的内部类对象。

    再来看看外部类调用内部类的情况:

     

     

    可以看到,无法调用到内部类的属性,因为没有内部类的对象,我们构建一个内部类参数传入方法中,试试

    public class OuterAndInnerClass
    {
        private int number;
    
        public void getInnerClassField(InnerClass inner){
            System.out.println(inner.name);
        }
    
        class InnerClass{
            private String name = "name";
            public void getOuterField(){
                System.out.println("inner class: " + number);   // inner class: 0
            }
        }
    
        public static void main(String[] args)
        {
            OuterAndInnerClass outer = new OuterAndInnerClass();
            InnerClass inner = outer.new InnerClass();
    //        inner.getOuterField();
            outer.getInnerClassField(inner);  // name
    
        }
    }

    虽然可以调用到内部类的属性,但是这个作为方法参数传入的,并不是直接调的。若不采用传内部类到方法中,也可以为外部类定义个内部类的属性,通过该属性调用

     

     

    但这样的调用与内部类直接访问外部类的属性是不同意义的。外部类和内部类的关系是:has a。那么,我们就要问问,内部类是怎么调用到外部类的属性的?

     

    2. 内部类是如何访问外部类的属性?

      我们知道类的方法隐含了两个参数:this和super。this指代的是当前对象,super指代的是父类对象,我们打印内部类中的this和super看是否指向InnerClass和Object

    package onehundred;
    
    public class OuterAndInnerClass
    {
        private int number;
    
        class InnerClass{
            private String name = "name";
            public void getOuterField(){
                System.out.println("this " + this.getClass().getName());  // this onehundred.OuterAndInnerClass$InnerClass
                System.out.println("super " + super.getClass().getName()); // super onehundred.OuterAndInnerClass$InnerClass
                System.out.println("inner class: " + number);   // inner class: 0
            }
        }
    
        public static void main(String[] args)
        {
            OuterAndInnerClass outer = new OuterAndInnerClass();
            InnerClass inner = outer.new InnerClass();
            inner.getOuterField();
    //        outer.getInnerClassField(inner);  // name
        }
    }

    打印发现,this和super竟然都指向内部类,内部类没有写extends不应该默认继承Object类吗?为什么super是内部类本身?

    还记得getClass()在哪里定义吗?Object类中该方法被定义为final,所以this.getClass()和super.getClass()调用的是同一个方法,由于getOuterField()是InnerClass类调用,所以打印出来都是InnerClass类。正确的调用应该使用getSuperClass()

    package onehundred;
    
    public class OuterAndInnerClass
    {
        private int number;
    
        class InnerClass{
            private String name = "name";
            public void getOuterField(){
                System.out.println("this " + this.getClass().getName());  // this onehundred.OuterAndInnerClass$InnerClass
                System.out.println("super " + super.getClass().getName()); // super onehundred.OuterAndInnerClass$InnerClass
                System.out.println("super " + this.getClass().getSuperclass().getName()); // super java.lang.Object
                System.out.println("inner class: " + number);   // inner class: 0
            }
        }
    
        public static void main(String[] args)
        {
            OuterAndInnerClass outer = new OuterAndInnerClass();
            InnerClass inner = outer.new InnerClass();
            inner.getOuterField();
    //        outer.getInnerClassField(inner);  // name
        }
    }

    既然this指向当前对象,super指向父类对象,那内部类是如何调用的外部类属性呢?

    我们使用javap将代码反编译。

    class onehundred.OuterAndInnerClass$InnerClass {
      final onehundred.OuterAndInnerClass this$0;
      onehundred.OuterAndInnerClass$InnerClass(onehundred.OuterAndInnerClass);
      public void getOuterField();
    }

    我们发现内部类多了一个外部类的final字段和一个带参构造器,外部类的引用有了,但是是如何访问到外部类的private字段的?

    我们反编译外部类:

    public class onehundred.OuterAndInnerClass {
      public onehundred.OuterAndInnerClass();
      public static void main(java.lang.String[]);
      static int access$000(onehundred.OuterAndInnerClass);
    }

    外部类多个一个static方法,并返回一个int型的值。内部类就是通过调用这个static方法得到了外部类的private字段。如果我们在内部类中访问外部类的boolean型字段,static方法就会返回一个boolean型的值。

    总结:

      可以在内部类中访问外部类的域,因为一个方法可以引用调用这个方法的对象数据域。内部类的对象总有一个隐式引用,它指向了创建它的外部类对象。这个引用在内部类的定义中是不可见的。

           外围类的引用在内部类的构造器中设置,编译器修改了所有内部类的构造器,添加一个外部类引用的参数。