把一个类放在另一个类内部定义,即为内部类。
一、非静态内部类
二、静态内部类
三、局部内部类
四、匿名内部类
其中前面两个是类成员,我们可以称作为成员内部类,既然作为成员,那么就像成员变量一样,可以使用private、protected、public、默认、static这样的修饰符。
-----------------------------------------------------------------------------------------------------------------
接下来我们依次进行讨论:
- 非静态内部类:
- 可以访问外部类的成员变量,不用管是private还是啥的,外部类的一切都可以访问;外部类不可以直接使用非静态内部类的成员,如果要使用则必须显示创建非静态内部类对象来访问,可以看3。
原因:非静态内部类对象里,保存了一个他所寄生的外部类对象的引用。
2. 对于外部类成员变量、非静态内部类成员变量、非静态内部类方法的局部变量同名的情况
外部类名字.this.成员变量名 this.成员变量名 局部变量名
public class Outer{
private String prop="外部prop";
private class Inner{
private String prop="内部prop";
public void info(){
String prop="方法prop";
System.out.println(prop);
System.out.println(this.prop);
System.out.println(Outer.this.prop);
}
}
}
3. 不允许在外部类的静态成员中直接使用非静态内部类
class Outer{
class Inner{
private int prop=5;
//private static int x;//错误的,不允许在非静态内部类定义任何静态的东西
}
public void test1(){
System.out.println(new Inner().prop);
}
public static void test2(){
//System.out.println(new Inner().prop);//错误的,不允许在外部类的静态成员中直接使用非静态内部类
}
}
4. 编译会生成两个文件:Outer.class Outer$Inner.class5. 非静态内部类必须寄生在外部类对象里,而外部类对象则不必一定有非静态内部类对象寄生其中。这也就解释了为什么外部类对象不可以访问非静态内部类成员,因为可能非静态内部类对象根本就不存在。
- 静态内部类:属于外部类本身,而不是外部类的某个对象
1. 只能访问外部类的静态成员(类成员),而不能访问实例变量
2. 静态内部类不是寄生在外部类对象,而是寄生在外部类的类本身当中。当静态内部类对象存在的时候,不一定存在一个被他寄生的外部类对象,他只有外部类的引用,没有外部类对象的引用。
3. 外部类仍然不可以直接访问内部类的成员。如果要使用则必须显示创建非静态内部类对象来访问(针对实例成员) 或者 使用内部类的类名来访问(针对静态成员)。
总结一句话:
静态内部类里面可以定义静态的和非静态的成员变量、方法...,可以随意访问外部类的静态的一切
非静态内部类只能定义非静态的成员变量、方法...,可以随意访问外部类的一切
外部类访问静态内部类,对于静态的,用类名.XXX, 对于非静态的,用new 内部类名().XXX
外部类访问非静态内部类,因为非静态内部类根本没有非静态的东东了,当然就是用new 内部类名().XXX
-----------------------------------------------------------------------------------------------------------------
在外部类的外面使用内部类:
非静态内部类: 外部类名.内部类名 变量名=new 外部类名().new 内部类名();
静态内部类: 外部类名.内部类名 变量名=new 外部类名.内部类名();
补充:如果一个类继承了非静态内部类,那么必须让子类构造器可以调用父类构造器,调用非静态内部类的构造器的时候,必须存在一个外部类对象。
比如:
public class SubClass extends Out.In{
public SubClass(Out out){
out.super();//调用父类的构造器,父类是Out类的非静态内部类
}
}
创建非静态内部类In对象和他的子类都应该持有Out对象的引用,只是他们传入的方式不同:
当创建非静态内部类In类的对象的时候,必须通过Out对象来调用new关键字;
当创建SubClass类的对象时,必须使用Out对象作为调用者来调用In类的构造器。
-----------------------------------------------------------------------------------------------------------------
- 局部内部类:在方法里定义,不能使用static修饰
外部类的名字$N局部内部类的名字.class
- 匿名内部类:匿名内部类不能是抽象类;不能定义构造器,但匿名内部类可以定义初始化块
被匿名内部类访问的局部变量,可以用final修饰,也可以不用final修饰,但必须按照有final修饰的方式来用。也就是一次赋值之后,以后不可以再次重新赋值。