第十章 内部类
可以将一个类的定义放在另一个类的定义内部,这就是内部类
1.创建内部类
创建内部类的方式:把类的定义置于外围类的里面
如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须具体地指明这个对象的类型:OutClassName.InnserClassName
2.链接到外部类
内部类能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有外围类的所有元素的访问权。
3.使用.this与.new
如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this。这样产生的引用自动地具有正确的类型
如果你想要告知某些其他对象,去创建其某个内部类对象,必须在new表达式中提供对其他外部类对象的引用,还需要用到.new语法
OutClass out = new OutClass();
OutClass.Inner inner = out.new Inner();
在拥有外部类对象之前是不可能创建内部类对象的。因为内部类对象会暗暗地连接到创建它的外部类对象上。但是如果你创建的
是嵌套类(静态内部类),那么它就不需要对外部类对象的引用。
4.内部类与向上转型
当将内部类向上转型为其基类,尤其是转型为一个接口的时候,此内部类--某个接口的实现--能够完全不可见,并且不可用。
所得到的只是指向基类或接口的引用,所以能够很方便地隐藏实现细节。
5.在方法和作用域内的内部类
局部内部类:在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类,也可以在任意的作用域内嵌入一个内部类。
6.匿名内部类
如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是fianl的。
通过实例初始化,就能够达到为匿名内部类创建一个构造器的效果。
7.嵌套类
如果不需要内部类与其外围类对象之间有联系,那么可以将内部类声明为static,通常称为嵌套类
普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static时,要创建嵌套类的对象,
并不需要其外围类的对象,不能从嵌套类的对象中访问非静态的外围类对象。
嵌套类与普通内部类还有一个区别,普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static
数据和static字段,也不能包含嵌套类。但是嵌套类可以包含所有这些东西。
7.1接口内部的类
正常情况下,不能在接口内部放置任何代码。但嵌套类可以作为接口的一部分。接口中的任何类都自动地是public和static的。
因为类是static的,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。也可以在内部类中实现其外围接口。
7.2从多层嵌套类中访问外部类的成员
一个内部类被嵌套多少层并不重要--它能透明地访问所有它所嵌套的外围类的所有成员。
8.为什么需要内部类
一般来说,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。
每个内部类都能独立地继承自一个接口的实现,所以无论外围类是否继承了某个(接口的)实现,对于内部类都没有影响。
8.1闭包与回调
闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。内部类是面向对象的闭包。
8.2内部类与控制框架
9.内部类的继承
因为内部类的构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候,事情会变得有点复杂。问题在于,那个指向
外围类对象的“神秘的”引用必须被初始化,而在导出类中不再存在可连接的默认的对象。
enclosingClassReference.super();
10.内部类可以被覆盖吗?
继承其外围类并重新定义此内部类时,原内部类不会被覆盖,这两个内部类是完全独立的两个实体。
11.局部内部类
可以在代码块里创建内部类,典型的方式是在一个方法体的里面创建。局部内部类不能有访问说明符,因为它不是外围类的一部分
但是他可以访问当前代码块内的常量,以及次外围类的所有成员。
12.内部类标示符
由于每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息。内部类也必须生成一个.class文件
这类文件的命名有严格的规定:外围类的名字,加上"$",再加上内部类的名字。
如果内部类是匿名的,编译器会简单的产生一个数字作为其标示符。
如果内部类是嵌套在别的内部类之中,只需要直接将它们的名字加在其外围类标示符与"$"的后面。