面向对象封装,继承,多态(二)

五:再谈继承
继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种
明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称
为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),
而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和
实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。私有成
员能继承,但是由于访问权限的控制,在子类中不能直接使用父类的私有成
员。并且 java 中是单继承,一个子类只能有一个父类
继承中的构造方法
当生成子类对象时,Java 默认首先调用父类的不带参数的构造方法,然
后执行该构造方法,生成父类的对象。接下来,再去调用子类的构造方法,
生成子类的对象。【要想生成子类的对象,首先需要生成父类的对象,没有
父类对象就没有子类对象。比如说:没有父亲,就没有孩子】。
如果子类使用 super()显式调用父类的某个构造方法,那么在执行的时候
就会寻找与 super()所对应的构造方法而不会再去寻找父类的不带参数的构
造方法。与 this 一样,super 也必须要作为构造方法的第一条执行语句,前
面不能有其他可执行语句。
当两个方法形成重写关系时,可以在子类方法中通过 super.run()形式调
用父类的 run()方法,其中 super.run()不必放在第一行语句,因此此时父类对
象已经构造完毕,先调用父类的 run()方法还是先调用子类的 run()方法是根
据程序的逻辑决定的。
方法的覆盖(重写)
重写的要求:子类覆盖方法和父类被覆盖方法的方法返回类型,方法名称,
参数列表必须相同
子类覆盖方法的访问权限必须大于等于父类的方法的访问权限
方法覆盖只能存在于子类和父类之间
子类覆盖方法不能比父类被覆盖方法抛出更多异常
方法重写与方法重载之间的关系:重载发生在同一个类内部的两个或多个方
法。重写发生在父类与子类之间。
final 关键字在继承中的使用
final 可以用于以下四个地方:
定义变量,包括静态的和非静态的。
如果 final 修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,
即它是个常量;如果 final 修饰的是一个对象,就表示这个变量被赋予的引用
是不可变的,不可改变的只是这个变量所保存的引用,并不是这个引用所指
向的对象,其实更贴切的表述 final 的含义的描述,那就是,如果一个变量或
方法参数被 final 修饰,就表示它只能被赋值一次,但是 JAVA 虚拟机为变量
设定的默认值不记作一次赋值。
被 final 修饰的变量必须被初始化。初始化的方式有以下几种:
1. 在定义的时候初始化。
2. 在初始化块中初始化。
3. 在类的构造器中初始化。
4. 静态变量也可以在静态初始化块中初始化。
1) 定义方法。
当 final 用来定义一个方法时,它表示这个方法不可以被子类重写,但是它这
不影响它被子类继承。
说明:
具有 private 访问权限的方法也可以增加 final 修饰,但是由于子类无法继承
private 方法,因此也无法重写它。编译器在处理 private 方法时,是按照 final
方法来对待的,这样可以提高该方法被调用时的效率。不过子类仍然可以定
义同父类中的 private 方法具有同样结构的方法,但是这并不会产生重写的效
果,而且它们之间也不存在必然联系。
3)定义类。
由于 final 类不允许被继承,编译器在处理时把它的所有方法都当作 final 的,
因此 final 类比普通类拥有更高的效率。final 的类的所有方法都不能被重写,
但这并不表示 final 的类的属性(变量)值也是不可改变的,要想做到 final
类的属性值不可改变,必须给它增加 final 修饰。
关于继承的几点注意:
a) 父类有的,子类也有
b) 父类没有的,子类可以增加
c) 父类有的,子类可以改变
d) 构造方法不能被继承
e) 方法和属性可以被继承
f) 子类的构造方法隐式地调用父类的不带参数的构造方法
g) 当父类没有不带参数的构造方法时,子类需要使用 super 来显
式地调用父类的构造方法,super 指的是对父类的引用
h) super 关键字必须是构造方法中的第一行语句。
六:然后议多态
多态(Polymorphism):用我们通俗易懂的话来说就是子类就是父类(猫是
动物,学生也是人),因此多态的意思就是:父类型的引用可以指向子类的
对象。
方法的重写、重载与动态连接构成多态性。Java 之所以引入多态的概念,原
因之一是它在类的继承问题上和 C++不同,后者允许多继承,这确实给其带
来的非常强大的功能,但是复杂的继承关系也给 C++开发者带来了更大的麻
烦,为了规避风险,Java 只 允许单继承,派生类与基类间有 IS-A 的关系(即
“猫”is a “动物”)。这样做虽然保证了继承关系的简单明了,但是势必在功能
上有很大的限制,所以,Java 引入了多态性的概念以弥补这点的不足,此外,
抽象类和接 口也是解决单继承规定限制的重要手段。同时,多态也是面向
对象编程的精髓所在。
在一个类中,可以定义多个同名的方法,只要确定它们的参数个数和类型不
同,这种现象称为类的多态。类的多态性体现在两方面:一是方法的重载上,
包括成员方法和构造方法的重载;二是在继承过程中,方法的重写。
多态性是面向对象的重要特征。方法重载和方法覆写实际上属于多态性的一
种体现,真正的多态性还包括对象多态性的概念。
对象多态性主要是指子类和父类对象的相互转换关系。
a) 向上类型转换(upcast):比如说将 Cat 类型转换为 Animal 类型,即将
子类型转换为父类型。对于向上类型转换,不需要显式指定。
b) 向下类型转换(downcast):比如将 Animal 类型转换为 Cat 类型。即将
父类型转换为子类型。对于向下类型转换,必须要显式指定(必须要使用强
制类型转换)。
网上摘抄的一段多态小总结:
1. Java 中除了 static 和 final 方法外,其他所有的方法都是运行时绑定的。在
我另外一篇文 章中说到 private 方法都被隐式指定为 final 的,因此 final 的
方法不会在运行时绑定。当在派生类中重写基类中 static、final、或 private
方法时,实质上是创建了一个新的方法。
2.在派生类中,对于基类中的 private 方法,最好采用不同的名字。
3.包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中
包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,
为不同的子类提供通用的接口。
4.对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因
为大家都知道 Java 垃圾回收器。
5.在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始
化顺序。
6.构造方法是被隐式声明为 static 方法。
7.用继承表达行为间的差异,用字段表达状态上的变化。
七、大谈抽象
抽象类(abstract class):使用了 abstract 关键字所修饰的类叫做抽象类。
抽象类无法实例化,也就是说,不能 new 出来一个抽象类的对象(实例)。
抽象方法(abstract method):使用 abstract 关键字所修饰的方法叫做抽象
方法。抽象方法需要定义在抽象类中。相对于抽象方法,之前所定义的方法
叫做具体方法(有声明,有实现)。
如果一个类包含了抽象方法,那么这个类一定是抽象类。
如果某个类是抽象类,那么该类可以包含具体方法(有声明、有实现)。
如果一个类中包含了抽象方法,那么这个类一定要声明成 abstract class,也
就是说,该类一定是抽象类;反之,如果某个类是抽象类,那么该类既可以
包含抽象方法,也可以包含具体方法。
无论何种情况,只要一个类是抽象类,那么这个类就无法实例化。
在子类继承父类(父类是个抽象类)的情况下,那么该子类必须要实现父类
中所定义的所有抽象方法;否则,该子类需要声明成一个 abstract class。 八:最后谈接口
Java 语言不支持一个类有多个直接的父类(多继承),但现实例子中,又有
很多类似于多继承的例子,比如教师,他的父类既可以是人,也可以是父母,
所以,在 java 中就用继承来填充这个空缺,java 不可以多继承, 但可以实
现(implements)多个接口,间接的实现了多继承。
Java 接口的特征归纳:
1, Java 接口中的成员变量默认都是 public,static,final 类型的(都可省略),必须
被显示初始化,即接口中的成员变量为常量(大写,单词之间用”_”分隔)
2, Java 接口中的方法默认都是 public,abstract 类型的(都可省略),没有方法
体,不能被实例化
3, Java 接口中只能包含 public,static,final 类型的成员变量和 public,abstract
类型的成员方法
4, 接口中没有构造方法,不能被实例化
5, 一个接口不能实现(implements)另一个接口,但它可以继承多个其它的接

6, Java 接口必须通过类来实现它的抽象方法
public class A implements B{…}
7, 当类实现了某个 Java 接口时,它必须实现接口中的所有抽象方法,否则这个
类必须声明为抽象的
8, 不允许创建接口的实例(实例化),但允许定义接口类型的引用变量,该引用
变量引用实现了这个接口的类的实例
9, 一个类只能继承一个直接的父类,但可以实现多个接口,间接的实现了多继
承.
10、通过接口,可以方便地对已经存在的系统进行自下而上的抽象,对于任意
两个类,不管它们是否属于同一个父类,只有它们存在相同的功能,就能从中抽
象出一个接 口类型.对于已经存在的继承树,可以方便的从类中抽象出新的
接口,但从类中抽象出新的抽象类却不那么容易,因此接口更有利于软件系统
的维护与重构.对于两 个系统,通过接口交互比通过抽象类交互能获得更好
的松耦合.
11,、接口是构建松耦合软件系统的重要法宝,由于接口用于描述系统对外提
供的所有服务,因此接口中的成员变量和方法都必须是 public 类型的,确保外
部使用者 能访问它们,接口仅仅描述系统能做什么,但不指明如何去做,所有
接口中的方法都是抽象方法,接口不涉及和任何具体实例相关的细节,因此接
口没有构造方法, 不能被实例化,没有实例变量. 二, 比较抽象类与接口
相同点
1, 代表系统的抽象层,当一个系统使用一颗继承树上的类时,应该尽量把引用
变量声明为继承树的上层抽象类型,这样可以提高两个系统之间的送耦合
2, 都不能被实例化
3, 都包含抽象方法,这些抽象方法用于描述系统能提供哪些服务,但不提供具
体的实现
不同点:
1, 在抽象类中可以为部分方法提供默认的实现,从而避免在子类中重复实现
它们,这是抽象类的优势,但这一优势限制了多继承,而接口中只能包含抽象方
法.由于在 抽象类中允许加入具体方法,因此扩展抽象类的功能,即向抽象类
中添加具体方法,不会对它的子类造成影响,而对于接口,一旦接口被公布,就必
43
须非常稳定,因 为随意在接口中添加抽象方法,会影响到所有的实现类,这些
实现类要么实现新增的抽象方法,要么声明为抽象类
2, 一个类只能继承一个直接的父类,这个父类可能是抽象类,但一个类可以实
现多个接口,这是接口的优势,但这一优势是以不允许为任何方法提供实现作
为代价的 三, 为什么 Java 语言不允许多重继承呢?当子类覆盖父类的实例方
法或隐藏父类的成员变量及静态方法时,Java 虚拟机采用不同的绑定规则,假
如还允许一个类 有多个直接的父类,那么会使绑定规则更加复杂, 结论:
因此,为了简化系统结构设计和动态绑定机制,Java 语言禁止多重继承.而接口
中只有抽象方法,没有实例变量和静态方法,只有接口的实现类才会实现 接
口的抽象方法(接口中的抽象方法是通过类来实现的),因此,一个类即使有多
个接口,也不会增加 Java 虚拟机进行动态绑定的复杂度.因为 Java 虚拟机 永
远不会把方法与接口绑定,而只会把方法与它的实现类绑定.四, 使用接口和抽
象类的总体原则:
1, 用接口作为系统与外界交互的窗口站在外界使用者(另一个系统)的角度,接
口向使用者承诺系统能提供哪些服务,站在系统本身的角度,接口制定系统必
须实现哪 些服务,接口是系统中最高层次的抽象类型.通过接口交互可以提
高两个系统之间的送耦合系统 A 通过系统 B 进行交互,是指系统 A 访问系统
B 时,把引用变量声明 为系统 B 中的接口类型,该引用变量引用系统 B 中接
口的实现类的实例。
2, Java接口本身必须非常稳定,Java接口一旦制定,就不允许随遇更加,否则对
外面使用者及系统本身造成影响
3, 用抽象类来定制系统中的扩展点
抽象类来完成部分实现,还要一些功能通过它的子类来实现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值