java jdk7学习笔记:继承与多态

时间:2023-02-25 18:55:09

何谓继承

面向对象中,子类继承(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,:号之后表示返回类型,继承则以空心箭头表示。

java jdk7学习笔记:继承与多态

 

如何看出确实有继承了呢?从以下简单的程序可以看出:

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成员无法继承,那为什么上面的范例namelevelblood记录的值会显示出来呢?private成员会被继承,只不过子类无法直接存取,必须通过父类提供的方法来存取(如果父类愿意提供访问方法的话)。