第10章内部类

第10章内部类
1、可以将一个类的定义放在另一个类的定义内部,这就是内部类。
2、内部类是一种非常有用的特性,因为它允许把一些逻辑相关的类组织在一起,并控制位于内部的类的可见性。
10.1 创建内部类
1、如果从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须像在main方法中那样,具体地只能这个对象的类型 OuterClassName.InnerClassName
10.2 链接到外部类
1、当生产一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有元素的访问权。
2、内部类自动拥有对其外围类所有成员的访问权的原因如下:当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会捕获一个指向外围类对象的引用。然后,在你访问此外围类的成员时,就是用那个引用来选择外围类的成员。
3、内部类的对象只能在与其外围类的对象相关联的情况下才能被创建。
10.3使用.this与.new
1、在拥有外部类对象之前是不可能创建内部类对象的,这是因为内部类对象会连接到创建它的外部类对象上。但是,如果创建的是嵌套类(静态内部类),那么它就不需要对外部类对象的引用。

10.4 内部类与向上转型
1、当将内部类向上转型为其基类,尤其是转型为一个接口时,内部类会很有用。(从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质是一样的)
10.5在方法和作用域内的内部类
1、可以在一个方法里面或者任意的作用域内定义内部类。理由:
①实现了某类型的接口,可以创建并返回对其的引用
②要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。
2、①一个定义在方法中的类
②一个定义在作用域内的类,此作用域在方法的内部
③一个实现了接口的匿名类
④一个匿名类,它扩展了有非默认构造器的类。
⑤一个匿名类,它执行了字段初始化
⑥一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)
10.6匿名内部类
1、在匿名类中不可能有命名构造器(因为它根本没有名字),但通过实例初始化,就能够达到为匿名内部类创建一个构造器的效果。
2、对于匿名类而言,实例初始化的实际效果就是构造器。当然它受到限制–不能重载实例初始化方法,所以仅有一个这样的构造器。
3、匿名内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备。而且如果是实现接口,也只能实现一个接口。
10.6.1再访工厂方法
1、优先使用类而不是接口。如果设计中需要某个接口,必须了解它。
10.7 嵌套类
1、如果不需要内部类对象与其外围类对象职之间有联系,那么可以将内部类声明为static。通常称为嵌套类。
2、普通的内部类对象隐式地保存一个引用,指向创建它的外围对象。当内部类是static的时候,就不是这样的了。
3、嵌套类意味着:
①要创建嵌套类的对象,并不需要其外围类的对象。
②不能从嵌套类的对象访问非静态的外围类对象。
4、嵌套类与普通的内部类还有一个区别。普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。嵌套类可以包含这些东西。
5、在一个普通的(非static)内部类中,通过一个特殊的this引用可以链接到其外围类对象。嵌套类就没有这个特殊的this引用,这使得它类似于一个static方法。
10.7.1接口内部的类
1、正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分。接口中的任何类都自动地是public和static的。因为类是static的,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。
2、如果想要创建某些公共代码,使得可以被某个接口的所有不同实现所共用,那么使用接口内部的嵌套类会显得方便。
3、在每个类中都写一个main()方法,用来测试这个类。这样做有一个缺点,就是必须带着那些已编译过的额外代码。如果是个麻烦,则可以使用嵌套类来放置测试代码。
10.7.2从多层嵌套类中访问外部类的成员
1、一个内部类被嵌套多少层并不重要—-它能透明地访问所有它所嵌入的外围类的所有成员。
2、“.new”语法能产生正确的作用域,所以不必在调用构造器时限定类名。
10.8 为什么需要内部类
1、一般说来,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。所以可以认为内部类提供了某种进入其外围类的窗口。
2、内部类必须要回答的一个问题是:如果只是需要一个对接口的引用,为什么不通过外围类实现那个接口呢?答案是:“如果这能满足需求,那么久应该这样做”。那么内部类实现一个接口与外围类实现这个接口有什么区别呢?答案是:后者不是总能想用到接口带来的方便,有时需要用到接口的实现,所以使用内部类最吸引人的原因是:
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
3、如果没有内部类提供的、可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。
4、内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。也就是说,内部类允许继承多个非接口类型(类或抽象类)
5、如果拥有的是抽象的类或具体的类,而不是接口,那就只能使用内部类才能实现多重继承。
6、内部类可以有多个实例,每个实例都有自己的状态信息,并且与外围类对象的信息相互独立。
7、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。
8、创建内部类对象时刻并不依赖于外围类对象的创建
9、内部类并没有令人迷惑的“is-a”关系,它就是一个独立的实体。
10.8.1 闭包与回调
1、闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。
2、内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。
3、通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。
4、当创建了一个内部类时,并没有在外围类的接口中添加东西,也没有修改外围类的接口。
5、回调的价值在于它的灵活性—可以在运行时动态地决定需要调用什么方法。
10.8.2 内部类与控制框架
1、应用程序框架就是被设计用以解决某类特定问题的一个类或一组类。要运用某个应用程序框架,通常是继承一个类或多个类,并覆盖某些方法。在覆盖后的方法中,编写代码定制应用程序框架提供的通用解决方案,以解决你的特定问题模板方法的一个例子。
2、模板方法包含算法的基本结构,并且会调用一个或多个可覆盖的方法,以完成算法的动作。设计模式总是将变化的事物与保持不变的事物分离开,在这个模式中,模板方法是保持不变的事物,而可覆盖的方法就是变化的事物。
3、一个控制框架,它的工作就是在事件“就绪”的时候执行事件。虽然“就绪”可以指任何事,但在本例中是指基于事件触发的事件。
4、接口描述了要控制的事件。因为其默认的行为是基于时间去执行控制,所以使用抽象类代替实际的接口。
5、内部类允许:
①控制框架的完整实现是由单个的类创建的,从而使得实现的细节被封装了起来。内部类用来解决问题所必需的各种不同的动作。
②内部类能够很容易地访问外围类的任意成员。
10.9内部类的继承
1、内部类的构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候,那个指向外围类的对象的引用必须被初始化,而在导出类中不再存在可连接的默认对象。
2、若类只继承自内部类,而不是外围类。但是当要生成一个构造器时,默认的构造器并不算好,而且不能只是传递一个指向外围类对象的引用。此外,必须在构造器内部使用如下语法:enclosingClassReference.super(); 这样才提供了必要的引用,然后程序才能编译通过。
10.10 内部类可以覆盖嘛?
1、“覆盖”内部类是外围类的一个方法,其实并不起什么作用。
2、当继承了某个外围类的时候,内部类并没有发生变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。
10.11局部内部类
1、可以在代码块里创建内部类,典型的方法是在一个方法体的里面创建。局部内部类不能有访问说明符,因为它不是外围类的一部分;但是它可以访问当前代码块内的常量,以及此外围类的所有成员。
2、局部内部类的名字在方法外是不可见的,那么为什么仍然使用局部内部类而不是匿名内部类呢?因为需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。
3、使用局部内部类而不是匿名内部类的一个理由是:需要不止一个该内部类的对象。
10.12内部类标识符
1、每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息。
2、内部类也生成一个.class文件以及包含它们的Class对象信息。这些类文件的命名有严格的规则:外围类的名字,加上3”的后面。
10.13总结

猜你喜欢

转载自blog.csdn.net/panda_____/article/details/80274761
今日推荐