一、内部类的基本概念
略
二、内部类的实现原理
1. 普通内部类
先来建立一个简单的普通内部类
package inner.local;
import inner.InnerInterface;
public class Outer {
private int out_int = 3;
private void out_me () {}
class Inner implements InnerInterface{
private int in_int = 4;
@Override
public void getField () {
int in_int = out_int;
}
@Override
public void getMedthod() {
out_me();
}
}
}
将Outer.java编译后,会发现在同一包下生产了两个class文件,一个外部类文件Outer.class和一个内部类文件Outer$Inner.class
将他们分别反编译后的结果如下
public class Outer {
private int out_int = 3;
private void out_me() {
}
static int access$0(Outer outer) {
return outer.out_int;
}
static void access$1(Outer outer) {
outer.out_me();
}
}
class Outer$Inner implements InnerInterface {
private int in_int = 4;
//指向外部类的引用
final Outer this$0;
Outer$Inner(Outer paramOuter) {
this$0 = paramOuter;
}
public void getField() {
int in_int = Outer.access$0(this.this$0);
}
public void getMedthod() {
Outer.access$1(this.this$0);
}
}
结论:
- 普通内部类编译后会生成一个内部类文件(Outer$Inner.class);
- 普通内部类中含有一个指向外部类的引用(this$0);
- 普通内部类中需要访问外部类变量和方法时,会在外部类中生成相应的静态方法(access0和access1),通过指向外部类的引用(this0)来调用它的静态方法(access0和access$1)实现对外部类变量和方法的访问。
2.静态内部类
同理,写一个静态内部类实例
package inner.nest;
import inner.InnerInterface;
/**
* 静态内部类中可以嵌套静态类和其他内部类,可以包含静态成员和方法
*/
public class Outer {
//只能访问static变量
private static int out_int = 3;
//只能访问static方法
private static void out_me () {}
public static class Inner implements InnerInterface{
@Override
public void getField() {
int in_int = out_int;
}
@Override
public void getMedthod() {
out_me();
}
}
}
同理,编译后内部类也生成class文件
反编译后的结果如下:
public class Outer{
private static int out_int = 3;
private static void out_me() {};
//内部类可以访问的权限,因此不会生产额外的static方法
static void out_me2() {};
//为什么不直接调用静态属性、静态方法?
//为了增加private修饰的权限
static int access$0(Outer outer) {
return outer.out_int;
}
static void access$1(Outer outer) {
outer.out_me();
}
}
package inner.nest;
import inner.InnerInterface;
public class Outer$Inner implements InnerInterface {
public void getField() {
int in_int = Outer.access$0();
}
public void getMedthod() {
Outer.access$1();
Outer.out_me2();
}
}
结论:
- 静态内部类中没有包含外部类的引用
- 静态内部类中访问外部类变量和方法时,如果没有访问权限(out_int和out_me())则生成静态方法,如果拥有权限(out_me2())则不会生产额外方法
- 静态内部类只能访问外部类的静态属性
3.方法内部类和匿名内部类
略。
4.内部类访问的局部变量为什么不可变(必须final修饰)?
通过反编译文件,发现在Inner类中创建了一个局部变量的备份(因为方法的栈桢出栈后外部类的局部变量可能被回收)。将局部变量强制规定为final型,可以保持外部类中局部变量与内部类中的变量备份一致(如果没有final修饰,局部变量在外部类中修改,内部类中无法同时更改)。
可以通过添加额外构造器,将局部变量传入构造器来回避这种语法。
class inner.anonymous.Outer$1 implements inner.InnerInterface {
final inner.anonymous.Outer this$0;
//局部变量备份
private final inner.anonymous.Instance val$out_instance;
inner.anonymous.Outer$1(inner.anonymous.Outer, inner.anonymous.Instance);
public void getField();
public void getMedthod();
}
三、内部类的应该场景
-实现回调(内部类拥有更好的封装特性)
- 实现多继承
- 更好的封装(可以用private ,protected修饰)
- 内部类有更好的灵活性,可以访问外部类的所有成员和方法