java 内部类的实现原理

一、内部类原理

内部类(inner class) 是定义在类中的类。如下所示:

1 public class Outer{
2     private int num ; 
3     public class Inner implements Interface{
4        public void print(){
5             System.out.println(num);
6         }
7     }
8 }

 

使用内部类有几方面的考虑:

  1. 方便访问类中的所有数据,包括私有变量、私有方法

  2. 隐藏对其他类无关的类,比如实现了某个接口的回调类。

  3. 使用匿名类来简化代码


内部类是一种编译器现象,与虚拟机无关。编译器将内部类翻译成 外部类名$内部类名的常规类文件,JVM层面将其当作普通类文件处理。

使用javap 分析或者使用反射机制对类Outer$Inner进行分析,如下:

 1 // javap -p Outer
 2 '''外部类文件'''
 3 public class Outer{
 4     int num;
 5     static int access$0(Outer);
 6 }
 7 
 8 // javap -p Outer\$1Inner.class
 9 '''内部类文件'''
10 public class Outer$Inner{
11     final Outer this$0 ; 
12     public Outer$Inner(Outer);
13     public void print(); 
14     
15 }

 

这里把Outer对象通过构造函数构造进来,就是为了能够访问外围类,且这里是final修饰的,对应唯一。

可以看出内部类持有一个外部类引用,并且有一个隐式的构造器,初始化外部类实例变量。

 

而编译器在外围类中添加了一个静态方法access$0。为内部类提供外围类num属性的访问,它将返回作为参数的外部类实例的成员变量num。

默认修饰符加static是当前方法只能在同一个包下访问。而内部类正是通过编译器生成一个同一个包下的类,来实现内部类。

内部类中的 System.out.println(num)其实是 System.out.println( Outer.access$0(this$0))

 

内部类没有什么特殊的,其访问外围类数据的能力都是编译器添加代码实现的。

 

二、问题

1、匿名内部类为什么只能访问局部的final变量?

其实可以这样想,当方法执行完毕后,局部变量的生命周期就结束了,而局部内部类对象的生命周期可能还没有结束,那么在局部内部类中访问局部变量就不可能了,所以将局部变量改为final,改变其生命周期。

 

2、匿名内部类为什么访问外部类成员字段不用final?

上面说了,final关键字是为了解决数据不一致的问题,因为内部类中存有外部类的引用,所有对外部类中字段的修改都会真实的反映到外部类实例本身,所以不需要用final来修饰。

posted @ 2022-05-23 14:29  r1-12king  阅读(105)  评论(0编辑  收藏  举报