Topic: JAVA面试题解惑系列(九)——继承、多态、重载和重写

  Print this page

1.JAVA面试题解惑系列(九)——继承、多态、重载和重写 Copy to clipboard
Posted by: 臧圩人
Posted on: 2008-07-31 09:08

------------------------------------------------------------------------------------
我想出一本名为《JAVA面试题解惑系列》的书籍,详情请见:
http://rmyd.group.javaeye.com/group/topic/6193
目前网络连载中:http://zangweiren.javaeye.com/
请大家多关注,多提宝贵意见!
------------------------------------------------------------------------------------

作者:臧圩人(zangweiren)
网址:http://zangweiren.javaeye.com

>>>转载请注明出处!<<<

什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承、多态、重载和重写。

继承

简单的说,继承就是在一个现有类型的基础上,通过增加新的方法或者重定义已有方法(下面会讲到,这种方式叫重写)的方式,产生一个新的类型。继承是面向对象的三个基本特征--封装、继承、多态的其中之一,我们在使用JAVA时编写的每一个类都是在继承,因为在JAVA语言中,java.lang.Object类是所有类最根本的基类(或者叫父类、超类),如果我们新定义的一个类没有明确地指定继承自哪个基类,那么JAVA 就会默认为它是继承自Object类的。

我们可以把JAVA中的类分为以下三种:

1. 普通类:使用class定义且不含有抽象方法的类。
2. 抽象类:使用abstract class定义的类,它可以含有,也可以不含有抽象方法。
3. 接口类:使用interface定义的类。

在这三种类型之间存在下面的继承规律:

* 普通类可以继承(extends)普通类,可以继承(extends)抽象类,可以继承(implements)接口。
* 抽象类可以继承(extends)普通类,可以继承(extends)抽象类,可以继承(implements)接口。
* 接口只能继承(extends)接口。

请注意上面三条规律中每种继承情况下使用的不同的关键字extends和implements,它们是不可以随意替换的。大家知道,一个普通类继承一个接口后,必须这个接口中定义的所有方法,否则就只能被定义为抽象类。我在这里之所以没有对implements关键字使用“实现”这种说法是因为从概念上来说它也是表示一种继承关系,而且对于抽象类implements接口的情况下,它并不是一定要实现这个接口定义的任何方法,因此使用继承的说法更为合理一些。

以上三条规律同时遵守下面这些约束:

1. 普通类和抽象类都只能最多继承一个普通类,或者最多继承一个抽象类,并且这两种情况是互斥的,也就是说它们要么继承一个普通类,要么继承一个抽象类。
2. 普通类、抽象类和接口在继承接口时,不受数量的约束,理论上可以继承无限多个接口。当然,对于普通类来说,它必须实现它所继承的所有接口中定义的全部方法。

继承给我们的编程带来的好处就是对原有类的复用(重用)。就像模块的复用一样,类的复用可以提高我们的开发效率,实际上,模块的复用是大量类的复用叠加后的效果。除了继承之外,我们还可以使用组合的方式来复用类。所谓组合就是把原有类定义为新类的一个属性,通过在新类中调用原有类的方法来实现复用。如果新定义的类型与原有类型之间不存在被包含的关系,也就是说,从抽象概念上来讲,新定义类型所代表的事物并不是原有类型所代表事物的一种,比如黄种人是人类的一种,它们之间存在包含与被包含的关系,那么这时组合就是实现复用更好的选择。下面这个例子就是组合方式的一个简单示例:
Java代码 复制代码

1. public class Sub {
2. private Parent p = new Parent();
3.
4. public void doSomething() {
5. // 复用Parent类的方法
6. p.method();
7. // other code
8. }
9. }
10.
11. class Parent {
12. public void method() {
13. // do something here
14. }
15. }

当然,为了使代码更加有效,我们也可以在需要使用到原有类型(比如Parent p)时,才对它进行初始化。

使用继承和组合复用原有的类,都是一种增量式的开发模式,这种方式带来的好处是不需要修改原有的代码,因此不会给原有代码带来新的BUG,也不用因为对原有代码的修改而重新进行测试,这对我们的开发显然是有益的。因此,如果我们是在维护或者改造一个原有的系统或模块,尤其是对它们的了解不是很透彻的时候,就可以选择增量开发的模式,这不仅可以大大提高我们的开发效率,也可以规避由于对原有代码的修改而带来的风险。

多态

多态是又一个重要的基本概念,上面说到了,它是面向对象的三个基本特征之一。究竟什么是多态呢?我们先看看下面的例子,来帮助理解:
Java代码 复制代码

1. //汽车接口
2. interface Car {
3. // 汽车名称
4. String getName();
5.
6. // 获得汽车售价
7. int getPrice();
8. }
9.
10. // 宝马
11. class BMW implements Car {
12. public String getName() {
13. return "BMW";
14. }
15.
16. public int getPrice() {
17. return 300000;
18. }
19. }
20.
21. // 奇瑞QQ
22. class CheryQQ implements Car {
23. public String getName() {
24. return "CheryQQ";
25. }
26.
27. public int getPrice() {
28. return 20000;
29. }
30. }
31.
32. // 汽车出售店
33. public class CarShop {
34. // 售车收入
35. private int money = 0;
36.
37. // 卖出一部车
38. public void sellCar(Car car) {
39. System.out.println("车型:" + car.getName() + " 单价:" + car.getPrice());
40. // 增加卖出车售价的收入
41. money += car.getPrice();
42. }
43.
44. // 售车总收入
45. public int getMoney() {
46. return money;
47. }
48.
49. public static void main(String[] args) {
50. CarShop aShop = new CarShop();
51. // 卖出一辆宝马
52. aShop.sellCar(new BMW());
53. // 卖出一辆奇瑞QQ
54. aShop.sellCar(new CheryQQ());
55. System.out.println("总收入:" + aShop.getMoney());
56. }
57. }

运行结果:

1. 车型:BMW 单价:300000
2. 车型:CheryQQ 单价:20000
3. 总收入:320000

继承是多态得以实现的基础。从字面上理解,多态就是一种类型(都是Car类型)表现出多种状态(宝马汽车的名称是BMW,售价是300000;奇瑞汽车的名称是CheryQQ,售价是2000)。将一个方法调用同这个方法所属的主体(也就是对象或类)关联起来叫做绑定,分前期绑定和后期绑定两种。下面解释一下它们的定义:

1. 前期绑定:在程序运行之前进行绑定,由编译器和连接程序实现,又叫做静态绑定。比如static方法和final方法,注意,这里也包括private方法,因为它是隐式final的。
2. 后期绑定:在运行时根据对象的类型进行绑定,由方法调用机制实现,因此又叫做动态绑定,或者运行时绑定。除了前期绑定外的所有方法都属于后期绑定。

多态就是在后期绑定这种机制上实现的。多态给我们带来的好处是消除了类之间的耦合关系,使程序更容易扩展。比如在上例中,新增加一种类型汽车的销售,只需要让新定义的类继承Car类并实现它的所有方法,而无需对原有代码做任何修改,CarShop类的sellCar(Car car)方法就可以处理新的车型了。新增代码如下:
Java代码 复制代码

1. // 桑塔纳汽车
2. class Santana implements Car {
3. public String getName() {
4. return "Santana";
5. }
6.
7. public int getPrice() {
8. return 80000;
9. }
10. }

重载和重写

重载和重写都是针对方法的概念,在弄清楚这两个概念之前,我们先来了解一下什么叫方法的型构。型构就是指方法的组成结构,具体包括方法的名称和参数,涵盖参数的数量、类型以及出现的顺序,但是不包括方法的返回值类型,访问权限修饰符,以及abstract、static、final等修饰符。比如下面两个就是具有相同型构的方法:
Java代码 复制代码

1. public void method(int i, String s) {
2. // do something
3. }
4.
5. public String method(int i, String s) {
6. // do something
7. }

而这两个就是具有不同型构的方法:
Java代码 复制代码

1. public void method(int i, String s) {
2. // do something
3. }
4.
5. public void method(String s, int i) {
6. // do something
7. }

了解完型构的概念后我们再来看看重载和重写,请看它们的定义:

* 重写,英文名是override,是指在继承情况下,子类中定义了与其基类中方法具有相同型构的新方法,就叫做子类把基类的方法重载了。这是实现多态必须的步骤。
* 重载,英文名是overload,是指在同一个类中定义了一个以上具有相同名称,但是型构不同的方法。在同一个类中,是不允许定义多于一个的具有相同型构的方法的。

我们来考虑一个有趣的问题:构造器可以被重载吗?答案当然是可以的,我们在实际的编程中也经常这么做。实际上构造器也是一个方法,构造器名就是方法名,构造器参数就是方法参数,而它的返回值就是新创建的类的实例。但是构造器却不可以被子类重写,因为子类无法定义与基类具有相同型构的构造器。

2.Re:JAVA面试题解惑系列(九)——继承、多态、重载和重写 [Re: 臧圩人] Copy to clipboard
Posted by: JiafanZhou
Posted on: 2008-08-02 17:24

I am very glad to see that you have written 9 articles about various areas in Java. And constantly share your articles free with others. You really deserve to have some points here, Thanks you 臧圩人.

Couple of points related to this article:
- I think English terminologies are also important in the interviews.
e.g. Interviews should also know that 继承、多态、重载和重写 are "Inheritance, Polymorphism , overloading and overwriting" in English respectively. So maybe we could add them besides their Chinese names.
(I remember I used to read a book from "张洪斌", although maybe his book is the best, he explains theories in a very very understandable term. And he also dislikes the awkward Chinese translation to some computer terminologies)

>我们可以把JAVA中的类分为以下三种:
- Don't forget about the inner class.

> 3. 接口类:使用interface定义的类。
- Interface(s) are called interface(s). They should not be referred to as "Interface classes". It is confusing.

- This theory could be demonstrated very easily using images. e.g. Class diagrams would be a good option.

Regards,
Jiafan

3.Re:JAVA面试题解惑系列(九)——继承、多态、重载和重写 [Re: 臧圩人] Copy to clipboard
Posted by: 臧圩人
Posted on: 2008-08-03 17:46

回复HenryShanley:

没什么好说的,对你的建议再次表示感谢:)


   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923