目录
1. 内部类的作用
- 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。
- 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。匿名内部类适合用于创建那些仅需要一次使用的类。
2. 内部类与外部类的区别
- 外部类的上一级程序单元是包,所以它只有 2 个作用域:同一个包内和任何位置。因此只需 2 种访问权限:包访问权限和公开访问权限,正好对应省略访问控制符和 public 访问控制符。而内部类的上一级程序单元是外部类,它就具有 4 个作用域:同一个类、同一个包、父子类和任何位置,因此可以使用 4 种访问控制权限。对应private、protected、public访问控制符。
- 内部类可以使用static修饰,表示静态内部类。
3. 非静态内部类
- 在非静态内部类里可以直接访问外部类的 private 成员,这是因为在非静态内部类对象里,保存了一个它所寄生的外部类对象的引用(当调用非静态内部类的实例方法时,必须有一个非静态内部类实例 ,非静态内部类实例必须寄生在外部类实例里),OuterClass.this可以表示外部类对象引用。
- 非静态内部类对象必须寄生在外部类对象中,而外部类对象则不一定有非静态内部类对象寄生在其中。简单地说,如果存在一个非静态内部类对象,则一定存在一个被它寄生的外部类对象。但外部类对象存在时,外部内对象里不一定寄生了非静态内部类对象。因此外部类对象访问非静态内部类成员时,可能非静态内部类对象根本不存在!而非静态内部类对象访问外部类成员时,外部类对象一定存在。
- 非静态内部类里不能有静态方法、静态成员变量、静态初始化块。非静态内部类相当于外部类中的非静态成员变量,而如果外部类需要调用非静态成员变量就需要先实例化才可以,如果非静态内部类中有静态方法块,那么又可以在加载类的时候提前加载,不需要考虑外部类的实例化,所以有矛盾,所以不可以。
- 根据静态成员不能访问非静态成员的规则,外部类的静态方法、静态代码块不能访问非静态内部类 ,包括不能使用非静态内部类定义变量、 创建实例等 。 总之 , 不允许在外部类的静态成员中直接使用非静态内部类。如下所示。
4. 静态内部类
如果使用 static 来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。
- 静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
因为静态内部类是外部类的类相关的,而不是外部类的对象相关的。也就是说,静态内部类对象不是寄生在外部类的实例中,而是寄生在外部类的类本身中。当静态内部类对象存在时,并不存在一个被它寄生的外部类对象,静态内部类对象只持有外部类的类引用,没有持有外部类对象的引用。如果允许静态内部类的实例方法访问外部类的实例成员,但找不到被寄生的外部类对象,这将引起错误。 - 静态内部类是外部类的一个静态成员,因此外部类的所有方法、所有初始化块中可以使用静态内部类来定义变量、创建对象等。外部类依然不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。如下所示。
5. 局部内部类
如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类仅在该方法里有效。由于局部内部类不能在外部类的方法以外的地方使用,因此局部内部类也不能使用访问控制符和 static 修饰符修饰。
局部内部类是一个非常“鸡肋”的语法,在实际开发中很少定义局部内部类,这是因为局部内部类的作用域太小了:只能在当前方法中使用。大部分时候,定义一个类之后,当然希望多次复用这个类,但局部内部类无法离开它所在的方法,因此在实际开发中很少使用局部内部类。
6. 匿名内部类
匿名内部类适合创建那种只需要一次使用的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。
- 匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口 。
- 由于构造器的名字必须与类名相同, 而匿名类没有类名, 所以,匿名类不能有构造器。
7. 使用内部类
7.1 在外部类内部使用内部类
在外部类内部使用内部类时,与平常使用普通类没有太大的区别。一样可以直接通过内部类类名来定义变量,通过 new 调用内部类构造器来创建实例。唯一存在的一个区别是:不要在外部类的静态成员(包括静态方法和静态初始化块 )中使用非静态内部类,因为静态成员不能访问非静态成员。
7.2 在外部类以外使用非静态内部类
在外部类以外的地方定义内部类(包括静态和非静态两种)变量的语法格式如下:
OuterClass.InnerClass varName
由于非静态内部类的对象必须寄生在外部类的对象里,因此创建非静态内部类对象之前,必须先创建其外部类对象。在外部类以外的地方创建非静态内部类实例的语法如下:
OuterInstance.new InnerConstructor();
7.3 在外部类以外使用静态内部类
因为静态内部类是外部类类相关的,因此创建静态内部类对象时无须创建外部类对象。在外部类以外的地方创建静态内部类实例的语法如下:
new OuterClass.InnerConstructor()