Inner classes(内隐类)
inner class得以让你控制“某个class在另一个class中的可视性”。
位于methods和scopes之内的inner classes(内隐类)
你可以将inner classes置于函数之内或甚至置于任意程序范畴(scope)之内。
以下应用:
1. 定义与函数之内的class。
2. 定义于函数内某一段范畴(scope)内的class。
3. 一个匿名(anonymous)class,实现某个interface。
4. 一个匿名class,扩充某个“拥有non-default构造函数”之class。
5. 一个匿名class,执行数据成员初始化动作。
6. 一个匿名class,以实体(instance)初始化来执行构造动作。注意,匿名的inner classes不得拥有构造函数。
匿名(anonymous)inner class
当base class需要一个带有引数的构造函数时,只要将适当引数传入base class构造函数种。
如果你定义了某个匿名inner class,并且希望用到定义于匿名inner class之外的某个对象,编译器会限制该外部对象必须为final。
同时通过实体初始化(instance initialization)你可以实际完成一个匿名inner class的建构。
与外围(outer)class的连接关系
inner class天生具有对enclosing class之所有成员的访问权力。
static inner class(静态内隐类)
如果你不需要inner class对象和enclosing class对象之间的连接关系,你可以将inner class声明为static。如果你想了解这么声明的确切时机,记住,一般的inner class(也就是non-static inner class)会自动记录一个reference指向enclosing class的某个实例,而后者也就是此inner class对象的制造者。但是一旦你将inner class声明为static,上述说法就不成立。static inner class意味着:
1. 产生对象时,并不需要同时存在一个enclosing class实例。
2. 你无法在static inner class对象中访问enclosing实例成员。
一般而言,你不能将任何程序代码置于interface内,但static inner class却可以使interface的一部分。这是因为class既然被声明为static,也就不会破坏interface的规则-static inner class只不过是被置于interface的命名空间中罢了。
取用(referring)outer class的实例
在你需要产生一个reference指向outer class对象时,命名方式便是在outer class名称之后紧接一个句号,然后再接this。
如果你想直接产生inner class对象,你不能像你所想象地在new表达式中使用outer class的名称,你必须使用outer class的实例来产生inner class对象。如:
Parcell1 p = new Parcell1();
Parcell1.Contents c = p.new Contents();
因此,除非你已经拥有一个outer class对象,否则便无法产生其inner class对象。这是因为inner class对象会被暗中连接到某个outer class对象上,后者即该inner class对象的制造者。不过,如果你制作的是static inner class,那就不需要一个reference指向outer class对象了。
从多层嵌套class向外伸展触角
无论inner class被嵌套置放的层次有多深,其所有outer classes的成员都可以被它访问。
继承inner classes
由于inner class的构造函数必须连接到一个reference指向outer class对象身上,所以当你继承inner class时,事情便稍微复杂些。问题出在“指向outer class对象”的那个神秘的reference必须被初始化,但derived class之内不存有可连接的缺省对象。这个问题的答案是,使用专用语法,明确产生关联性:
class WithInner{
class Inner{}
}
public class IneritInner extends WithInner.Inner{
//!InheritInner(){} //Won’t compile
InheritInner (WithInner wi)
{
wi.super();
}
}
InheritInner继承的是inner class而非outer class。但是当编译至构造函数时,default构造函数有问题;而且你也不能够只是传入一个reference指向outer object,你还必须在构造函数中使用以下语法:
enclosingClassReference.super();
inner classes可被覆写么吗?
我们能否把inner class视为outer class的一个函数一样,覆写inner class呢?
不能的。
Inner classes的标识符
先是outer class名称,其后紧接“$”符号,然后再紧接inner class名称。如果inner class没有名称,编译器会自动产生数字,做为inner class的标识符。如果inner classes被嵌套置于其他inner classes之内,其名称就会直接附加于“$”符号与outer class标识符(可能多个)之后。
为什么需要inner classes?
关于inner classes的存在,最让人信服的理由是:
每个inner class都能够各自继承某一实现类(implementation)。因此,inner class不受限于outer class是否已继承自某一实现类。
如果少了inner class所提供的“继承自多个具象(concrete)或抽象(abstract)类”的能力,设计上和编程上的某些问题会变得十分棘手。所以,从某个角度来看inner class,你可以说它是多重继承问题的完整解决方案。interface能够解决其中一部分问题,但inner classes才能有效而实际地允许“多重实现继承(multiple implementation)”。也就是说,inner classes实际上允许你继承多个non-interface。
通过inner classes,你可以拥有下列几个额外性质:
1. inner class可以拥有多份实体(instances),每个实体都拥有专属的状态信息(state information),而这些信息和outer class对象的信息是相互独立的。
2. 在单一outer class内你可以拥有多个innner classes,每个都实现相同的interface,或以不同方式继承同一个class。
3. 产生inner class对象的时间点,不见得必须和产生outer class对象同时。
4. outer class和inner class之间不存在is-a的关系,inner class是独立个体。
Closures(终结)和Callbacks(回调)
所谓closure是一种可被调用的对象,它会记录一些信息,这些信息来自它的产生地所在的程序范畴(scope)。
让inner class提供closure功能,是完美的解决方案。比起指针来说,不仅更具有弹性,而且安全许多。
callback的价值在于其弹性-你可以在执行时期动态决定究竟要调用哪个函数。
Inner classes和control frameworks
所谓application framework,是一组“被设计用来解决特定某种问题”的classes。如果你想套用某个application framework,你得继承一个或多个classes,并覆写其中某些函数。通过被覆写的函数内的新版程序代码,便可将application framework所提供的通用解法特殊化,针对性地解决你的特定问题。
所谓control framework,其实就是一种特殊形式的application framework,用来解决“事件(events)回应”的需要。一个系统如果主要工作在于回应诸般事件,我们称为“事件驱动系统(event-driven-system)”。
Java Swing程序库便是一个control framework,优雅解决了GUI问题,并大量采用inner classes |