zoukankan      html  css  js  c++  java
  • 为什么内部类可以访问外部类的私有属性?

    使用工具:

    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型的值。

    总结:

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

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

          

  • 相关阅读:
    农夫安全第二季课程-3.vmware ESXIv2
    六、表达式:前缀&&后缀
    五、数据类型(1):整数&&带小数点的数
    四、变量和常量
    三、简单的输入输出
    二、第一个C程序:Hello World!
    一、环境的安装Dev-C++
    .Net基础之5——复杂数据类型
    .Net基础之4——流程控制
    .Net基础之3——运算符
  • 原文地址:https://www.cnblogs.com/datamining-bio/p/13870270.html
Copyright © 2011-2022 走看看