何谓继承
面向对象中,子类继承(Inherit)父类,避免重复的行为定义,不过并非为了避免重复定义行为就使用继承,滥用继承而导致程序维护上的问题时有所闻。如何正确判断使用继承的时机,以及继承之后如何活用多态,才是学习继承时的重点。
继承共同行为
继承基本上就是避免多个类间重复定义共同行为。以实际的例子来说明比较清楚,假设你正在开发一款RPG(Role-playing game)游戏,一开始设定的角色有剑士与魔法师。首先你定义了剑士类:
public class SwordsMan {
private String name; // 角色名称
private int level; // 角色等级
private int blood; // 角色血量
public void fight() {
System.out.println("挥剑攻击");
}
public int getBlood() {
return blood;
}
public void setBlood(int blood) {
this.blood = blood;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接着你为魔法师定义类:
public class Magician {
private String name; // 角色名称
private int level; // 角色等级
private int blood; // 角色血量
public void fight() {
System.out.println("魔法攻击");
}
public void cure() {
System.out.println("魔法治疗");
}
public int getBlood() {
return blood;
}
public void setBlood(int blood) {
this.blood = blood;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
你注意到什么呢?因为只要是游戏中的角色,都会具有角色名称、等级与血量,类中也都为名称、等级与血量定义了取值方法与设值方法,Magician中粗体字部分与SwordsMan中相对应的程序代码重复了。重复在程序设计上,就是不好的信号。举个例子来说,如果要将name、level、blood改为其他名称,那就要修改SwordsMan与Magician两个类,如果有更多类具有重复的程序代码,那就要修改更多类,造成维护上的不便。
如果要改进,就可以把相同的程序代码提升(Pull up)为父类:
Game1 Role.java
package cc.openhome;
public class Role {
private String name;
private int level;
private int blood;
public int getBlood() {
return blood;
}
public void setBlood(int blood) {
this.blood = blood;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这个类在定义上没什么特别的新语法,只不过是将SwordsMan与Magician中重复的程序代码复制过来。接着SwordsMan可以如下继承Role:
Game1 SwordsMan.java
package cc.openhome;
public class SwordsMan extends Role {
public void fight() {
System.out.println("挥剑攻击");
}
}
在这里看到了新的关键字extends,这表示SwordsMan会扩充Role的行为,也就是继承Role的行为,再扩充Role原本没有的fight()行为。从程序面上来说,Role中有定义的程序代码,SwordsMan中都继承而拥有了,并定义了fight()方法的程序代码。类似地,Magician也可以如下定义继承Role类:
Game1 Magician.java
package cc.openhome;
public class Magician extends Role {
public void fight() {
System.out.println("魔法攻击");
}
public void cure() {
System.out.println("魔法治疗");
}
}
Magician继承Role的行为,再扩充了Role原本没有的fight()与cure()行为。
在图6.1所示的这个类图中,第一格中Role表示类名称;第二格中name、level、blood表示数据成员;:号之后为各成员类型,-号表示private;第三格表示方法名称,+号表示public,:号之后表示返回类型,继承则以空心箭头表示。
如何看出确实有继承了呢?从以下简单的程序可以看出:
Game1 RPG.java
package cc.openhome;
public class RPG {
public static void main(String[] args) {
SwordsMan swordsMan = new SwordsMan();
swordsMan.setName("Justin");
swordsMan.setLevel(1);
swordsMan.setBlood(200);
System.out.printf("剑士:(%s, %d, %d)%n", swordsMan.getName(),
swordsMan.getLevel(), swordsMan.getBlood());
Magician magician = new Magician();
magician.setName("Monica");
magician.setLevel(1);
magician.setBlood(100);
System.out.printf("魔法师:(%s, %d, %d)%n", magician.getName(),
magician.getLevel(), magician.getBlood());
}
}
虽然SwordsMan与Magician并没有定义getName()、getLevel()与getBlood()等方法,但从Role继承了这些方法,所以就如范例中可以直接使用。执行的结果如下:
剑士:(Justin, 1, 200)
魔法师:(Monica, 1, 100)
继承的好处之一,就是若你要将name、level、blood改为其他名称,那就只要修改Role.java就可以了,只要是继承Role的子类都无须修改。
本文摘自:《java jdk7学习笔记》 第6章
购买地址:互动网:http://product.china-pub.com/199212
当当网:http://product.dangdang.com/product.aspx?product_id=22643687
有的书籍或文件会说,private成员无法继承,那是错的。如果private成员无法继承,那为什么上面的范例name、level、blood记录的值会显示出来呢?private成员会被继承,只不过子类无法直接存取,必须通过父类提供的方法来存取(如果父类愿意提供访问方法的话)。 |