`
qcyycom
  • 浏览: 180905 次
社区版块
存档分类
最新评论

Java程序员从笨鸟到菜鸟之(三)面向对象之封装,继承,多态(下)

    博客分类:
  • java
阅读更多

 

五:再谈继承

   继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。私有成员能继承,但是由于访问权限的控制,在子类中不能直接使用父类的私有成员。并且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
中除了staticfinal方法外,其他所有的方法都是运行时绑定的。在我另外一篇文 章中说到private方法都被隐式指定为final的,因此final的方法不会在运行时绑定。当在派生类中重写基类中staticfinal、或 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, 用抽象类来定制系统中的扩展点

抽象类来完成部分实现,还要一些功能通过它的子类来实现 

更多信息请查看 java进阶网 http://www.javady.com

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics