前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >灵魂拷问:Java内部类是如何访问外部类私有对象的?

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

作者头像
好好学java
发布2021-03-11 14:18:51
2.5K0
发布2021-03-11 14:18:51
举报

作者:Aaron涛

blog.csdn.net/qq_33330687/article/details/77915345

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

代码语言:javascript
复制
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还多了三个静态的方法,这三个方法不是我们手写的。是编译器自动生成的,什么作用呢。

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

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

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

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

代码语言:javascript
复制
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

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

代码语言:javascript
复制
Field this$0:LOutClass;

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

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

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

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

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

结论

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

推荐文章

代码语言:javascript
复制
老板:kill -9的原理都不知道就敢到线上执行,明天不用来了
2020年国内互联网公司的薪酬排名!
我把 Spring Boot 的 banner 换成了美女,老板说工作不饱和,建议安排加班
写博客能月入10K?
一款基于 Spring Boot 的现代化社区(论坛/问答/社交网络/博客)
代码语言:javascript
复制
更多项目源码
这或许是最美的Vue+Element开源后台管理UI推荐一款高颜值的 Spring Boot 快速开发框架
一款基于 Spring Boot 的现代化社区(论坛/问答/社交网络/博客)
13K点赞都基于 Vue+Spring 前后端分离管理系统ELAdmin,大爱想接私活时薪再翻一倍,建议根据这几个开源的SpringBoot项目
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 好好学java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档