成员内部类
局部内部类
匿名内部类
静态内部类
1.静态内部类
声明在类的内部,方法体之外
使用static修饰
相当于类的静态变量和静态方法
可以脱离外部类的实例创建静态内部类的实例对象
(1)在外部类的外部创建静态内部类的实例
new Outer.Inner();
(2)在外部类的内部创建静态内部类的实例
new Inner();
在静态内部类的内部可以直接访问外部类的静态的资源(包括私有的静态资源),只能访问静态资源(类似于,静态方法只能调用静态资源)
2.成员内部类(实例内部类)
声明在类的内部,方法体之外
相当于类的成员变量和成员方法
成员内部类的实例化必须依赖于外部类
成员内部类中不允许声明静态变量和静态方法
原因:static的变量和方法,在类加载的时候就会存在于内存;要想使用一个类的静态资源,这个类首先必须加载到虚拟机中;
成员内部类的实例化必须依赖于外部类,换句话说,成员内部类并不会随外部类的加载而加载,只有实例化外部类之后才会加载
静态资源在类加载的时候存入内存,但是,成员内部类在类加载阶段并不会加载,在外部类实例化之后才会加载
成员内部类可以访问外部类的所有属性和方法(包括私有的、静态的)
原因:编译器编译时,会默认给内部类添加一个指向外部类的引用,并且在创建内部类实例的时候,将该指向内部类的引用初始化
在内部类有一个隐含的构造器,添加一个默认的参数去初始化内部类中指向外部类的引用
对于外部类的私有成员,外部类的class文件中多了一个针对私有成员的静态方法(default),内部类访问外部类的私有成员时,通过调用该静态方法调用目标成员
但是,外部类访问内部类的成员时,必须先创建内部类的对象,再通过内部类的对象访问内部类的资源
成员内部类实例的创建必须依赖于外部类的对象
(1)在外部类的外部创建成员内部类实例,必须依赖于外部类,所以,先创建外部类的实例,然后通过外部类的实例调用内部类的构造器
Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();
(2)在外部类的内部创建成员内部类的实例
Inner inner = new Inner();
在内部类中访问外部类的同名成员:外部类类名.this.成员变量&方法
访问修饰符,所有成员变量的访问修饰符都可以用来修饰成员内部类(private default protected public)
外部类的修饰符(public default)
编译之后,生成两个独立的class文件,Outer.calss Outer$Inner.class
编译器将内部类和外部类放在同一个包中。
内部类多了一个包可见(default)构造器,在创建内部类的实例时,实际上调用的是该包可见构造器,因此,即使内部类是private的,外部类也可以通过包可见构造器创建内部类的实例
内部类多了一个指向外部类的引用this$0,该引用在内部类的构造器中被初始化
- class Outer$Inner
- {
- Outer$Inner(Outer,Outer$Inner); //包可见构造器
- private Outer$Inner(Outer); //私有构造器将设置this$0域
- final Outer this$0; //外部类实例域this$0
- }
- class Outer
- {
- static int access$0(Outer); //静态方法,返回值是外部类私有域 data 的值。
- }
3.局部内部类
定义在方法体内或者一个作用域中
相当于方法里面的局部变量
不能使用访问控制符修饰
局部内部类对外部类是不可见的
但是,局部内部类可以访问外部类的成员
方法体中访问局部内部类,只能在定义语句之后
局部内部类只能访问方法体中的常量(final)
原因:局部变量的值在编译期间就确定了
4.匿名内部类
没有构造器
主要用于实现接口,并仅对接口方法的重写
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("----");
}
});