Thinking in Java第七章阅读小结

来源:互联网 发布:mac装win10后黑屏 编辑:程序博客网 时间:2024/05/02 16:11

 

第七章多态
7.1再论向上转型:
   将某个对象的引用视为对其基类型的引用的做法称作“向上转型”。
   我们可以利用这个原理,编写一个简单的方法,它仅接受基类作为参数,而不是那些特殊的导出类。这正是多态所允许的。
 
7.2 转机
 
1.方法调用绑定:
   将一个方法调用同一个方法主体联起来被称作“绑定”。前期绑定:在程序执行前进行绑定(如果有的话,由编译器和连接程序实现)。后期绑定:在运行时根据对象的类型进行绑定。也叫动态绑定。
   Java中,除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。这就意味着通常情况下,我们不必判定是否应该进行后期绑定——它会自动发生。
 
2.产生正确的行为:
   一旦知道Java中所有的方法都是通过动态绑定实现多态这个事实后,我们就可以编写只与基类打交道的程序代码了,并且这些代码对所有的导出类都可以正确运行。或者换一种说法,发送消息给某个对象,让该对象去断定应该做什么事。
 
3.可扩展性:
   在设计良好的OOP程序中,大多数或者所有方法都会遵循tune()的模型,而且只与基类接口通信。这样的程序是“可扩展的”,因为可以从通用的基类继承出新的数据类型,从而新添一些功能。那些操纵基类接口的方法不需要任何改动就可以应用于新类。
   多态是一项让程序员“将改变的事物与未变的事物分离开来”的重要技术。
 
4.缺陷:“覆盖”私有方法:
   只有非private方法才可以被覆盖,但是还需要密切注意覆盖private方法的现象,这是虽然编译器不会抱错,但是也不会按照我们所期望的来执行。确切的说,在导出类中,对于基类中的private方法,最好采用不同的名字。
 
7.3 抽象类和抽象方法:
抽象类:建立一个通用接口,不同的子类可以用不同的方式表示此接口。通用接口建立起一种基本形式,以此表示所有导出类的共同部分。
抽象方法:仅有声明没有方法体。语法如:abstract void f(); 包含抽象方法的类叫做“抽象类”。
如果一个抽象类不完整,那么当我们试图产生该类的对象时,为抽象类创建的对象是不安全的,所以我们会从编译器那里得到一条出错信息,确保不误用它。
如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类中所有的抽象方法提供方法定义。否则导出类也是抽象类,编译器会强制我们用abstract关键字来限定这个类。
也有可能会创建一个没有任何抽象方法的抽象类。当出现如下情况时,这样做是有用的:有一个类,让其包含任何abstract方法都显得没有任何实际意义,而我们想要阻止产生这个类的任何对象。
创建抽象类和抽象方法非常有用,因为它们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样来使用它们。
 
7.4 构造器和多态:
 
1.构造器的调用顺序:
   基类的构造器总是在导出类的构造过程中被调用,而且按照继承层次逐渐向上链接,以使每个基类的构造器都能得到调用。在导出类的构造器主体中,如果没有明确指定调用某个基类构造器,它就会“默默”的调用缺省构造器。如果不存在缺省构造器,编译器就会抱错(若类没有构造器,编译器会自动合成一个缺省构造器)。
 
2.继承与清理:
   如果要回收内存之外的东西,必须自己创建dispose()方法(可选用别的名称),由于继承的缘故,如果我们有其他作为垃圾回收一部分的特殊清理动作,就必须在导出类中覆盖dispose()方法。当覆盖基类的dispose()方法时,务必记住调用基类版本的dispose()方法,否则,基类的清理动作就不会发生。
 
3.构造器内部的多态方法的行为:
   在构造器内部调用一个动态绑定的方法,就要用到那个方法的被覆盖后的定义,然而,产生的效果可能相当难于预料,并且可能造成一些难于发现的隐藏错误。
编写构造器时有一条有效的准则:“用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其他方法”。在构造器内唯一能够安全调用的那些方法是基类中的final方法(也适用于private方法,它们自动属于final方法)。这些方法不能被覆盖。
 
7.5用继承进行设计:
  如果使用现成的类来建立新类时,如果首先考虑使用继承技术,反倒会加重我们的设计负担,使事情变得不必要的复杂起来。更好的方式是首先选择“组合”,尤其是不能十分确定应该使用哪一种方法时,组合不会强制我们的程序设计进入继承的层次结构中。而且,组合更加灵活,因为它可以动态的选择类型(因此也就选择了行为),相反,继承在编译时就需要知道确切类型。
   一条通用的准则是:用继承表达行为间的差异,并用字段表达状态上的变化。
 
1.纯继承与扩展:
“is-a”关系:导出类具有和基类一样的接口,是一种纯替代。
“is-like-a”关系:导出类就像是一个基类,它有着相同的基本接口,但它还有额外方法实现的其他特性。
“is-like-a”的缺点:导出类中接口的扩展部分不能被基类访问,因此,一旦我们向上转型,就不能调用那些新方法。
 
2.向下转型与运行时类型识别:
由于向上转型会丢失具体的类型信息,所以,通过向下转型——也就是在继承层次中向下移动——应该能够获取类型信息。
我们知道向上转型是安全的,因为基类不会具有大于导出类的接口。因此,我们通过 基类接口发送的消息保证都能被接受。
但向下转型必须有某种方法来确保安全性。使我们不致于贸然转到一种错误类型,进而发出该对象无法接受的消息。在Java语言中,所有转型都会得到检查!所以,即使我们只是进行一次普通的加括弧形式的类型转换,在进入运行期是仍会对其进行检查,以便保证它的确实我们希望的那种类型。如果不是,就会返回一个ClassCastException(类转型异常),我们不必为这个异常编写任何特殊的代码,因为它指出的是程序员在程序中任何地方都可能会犯的错误。
这种在运行期间对类型进行检查的行为称作“运行时类型识别(RTTI)”。
原创粉丝点击