五:再谈继承
???继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。私有成员能继承,但是由于访问权限的控制,在子类中不能直接使用父类的私有成员。并且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,?在抽象类中可以为部分方法提供默认的实现,从而避免在子类中重复实现它们,这是抽象类的优势,但这一优势限制了多继承,而接口中只能包含抽象方法.由于在?抽象类中允许加入具体方法,因此扩展抽象类的功能,即向抽象类中添加具体方法,不会对它的子类造成影响,而对于接口,一旦接口被公布,就必须非常稳定,因?为随意在接口中添加抽象方法,会影响到所有的实现类,这些实现类要么实现新增的抽象方法,要么声明为抽象类
2,?一个类只能继承一个直接的父类,这个父类可能是抽象类,但一个类可以实现多个接口,这是接口的优势,但这一优势是以不允许为任何方法提供实现作为代价的?三,?为什么Java语言不允许多重继承呢?当子类覆盖父类的实例方法或隐藏父类的成员变量及静态方法时,Java虚拟机采用不同的绑定规则,假如还允许一个类?有多个直接的父类,那么会使绑定规则更加复杂,
结论:
因此,为了简化系统结构设计和动态绑定机制,Java语言禁止多重继承.而接口中只有抽象方法,没有实例变量和静态方法,只有接口的实现类才会实现?接口的抽象方法(接口中的抽象方法是通过类来实现的),因此,一个类即使有多个接口,也不会增加Java虚拟机进行动态绑定的复杂度.因为Java虚拟机?永远不会把方法与接口绑定,而只会把方法与它的实现类绑定.四,?使用接口和抽象类的总体原则:
1,?用接口作为系统与外界交互的窗口站在外界使用者(另一个系统)的角度,接口向使用者承诺系统能提供哪些服务,站在系统本身的角度,接口制定系统必须实现哪?些服务,接口是系统中最高层次的抽象类型.通过接口交互可以提高两个系统之间的送耦合系统A通过系统B进行交互,是指系统A访问系统B时,把引用变量声明?为系统B中的接口类型,该引用变量引用系统B中接口的实现类的实例。
2,?Java接口本身必须非常稳定,Java接口一旦制定,就不允许随遇更加,否则对外面使用者及系统本身造成影响
3,?用抽象类来定制系统中的扩展点
抽象类来完成部分实现,还要一些功能通过它的子类来实现?