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

使用工具:

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

总结:

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

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

      

原文地址:https://www.cnblogs.com/datamining-bio/p/13870270.html