灵魂拷问:Java内部类是如何访问外部类私有对象的?

共 2831字,需浏览 6分钟

 ·

2021-03-12 18:52

点击上方 好好学java ,选择 星标 公众号

重磅资讯,干货,第一时间送达

今日推荐:14 个 github 项目!

个人原创100W +访问量博客:点击前往,查看更多

作者:Aaron涛
blog.csdn.net/qq_33330687/article/details/77915345

我们都是知道内部类就是写在一个类里面的类,类里面的类,不知道你们有没有看过javac之后的结果,就是将一个外部类编译后,生成的字节码文件结果

public class OutClass{
 
 private String name;
 private int id;
 private String address;
 
 
 
 public class innerClass{
  
  private String innerName;
  public void fun(){
   System.out.println(OutClass.this.name+": "+innerName);
   System.out.println(OutClass.this.id+": "+innerName);
   System.out.println(OutClass.this.address+": "+innerName);
  }
  public innerClass(String innerName){
   this.innerName = innerName;
  }
  
 }
}

这是我简单手写的一个外部类中嵌套一个内部类。

当我编译这段代码javac OutClass.java

可以看出会生成两个.class字节码文件,内部类的类名是外部类类名$内部类类名

然后对这个两个字节码文件反编译看看javap

可以看到,外部类OutClass除了默认构造器和私有的属性:name,id,address还多了三个静态的方法,这三个方法不是我们手写的。是编译器自动生成的,什么作用呢。

不晓得๑乛◡乛๑,然后看内部类OutClass$innerClass ,发现编译器也做了修改,首先,多了一个常量引用,final OutClass this$0 很明显,这就是指向外部类的引用,有了引用怎么对他赋值呢,然后我们看到了那个构造方法,我自己的源代码中构造方法的参数只有一个String innerName 而通过反编译我看到了多了一个参数,一个类型为OutClass,这就很明显了嘛。

编译器小哥偷偷的做了一些不可告人的事情,首先,内部类中多了个常量引用,准备指向着外部类,而且又偷偷修改了构造方法。传递一个OutClass类型的参数进去。这样内部类就拿到了外部类的引用。

但是仅仅拿到引用有个毛线用,通过反编译可以看到,生成的是两个字节码文件,在虚拟机看来,这就是两个不相关的类,你能在一个类中调用另外一个类的私有属性吗???

很明显不能。这个时候我做了个方法的测试呀,我们都知道,内部类使用外部类的属性用过外部类类名.this.属性名,所以我写了个测试方法fun

public void fun(){
   System.out.println(OutClass.this.name+": "+innerName);
   System.out.println(OutClass.this.id+": "+innerName);
   System.out.println(OutClass.this.address+": "+innerName);
  }

然后我们通过反编译看看这段代码怎么执行的。嘿嘿反编译真是个好东西(●´∀`●)4

javap -c OutClass$innerClass

看上去看不懂有点复杂,但是没关系我们看右边,看我红色箭头,是不是有点属性,

Field this$0:LOutClass;

Method OutClass.access$000:(LOutClass;)Ljava/lang/String;

截取一部分,看见没有,上面那个属性是内部类自动生成的常量指针,下面那个方法是外部类自动生成的三个静态方法。将指向外部类的引用作为参数给那三个外部类中的静态方法

然后我们去反编译看看那三个静态方法怎么实现的

又是祭出伟大的反编译工具

看得出,这三个方法都是返回外部类对应的私有属性!不过对于这点我还有点要说明,编译器很智能,它会扫描内部类,查看是否调用的外部类的私有属性,只有调用了才会生成对应的acess$xxx方法!

结论

在虚拟机中没有外部类内部类之分都是普通的类,但是编译器会偷偷的做点修改,让内部类中多一个常量引用指向外部类,自动修改内部类构造器,初始化这个常量引用,而外部类通过扫描内部类调用了外部类的那些私有属性,为这些私有属性创造acess$xxx静态方法。这个方法是返回对应的私有属性的值。所以可以在一个类的外部获取一个类的私有属性的值

推荐文章
更多项目源码

浏览 30
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报