抽象类_演练

原始代码

定义一个鸭子类(Duck)、一个狗类(Dog)和一个猫类(Cat),每个类都具备一个名字字段,且只能通过getName来访问,且都有一个speak方法。

public class Main {

    public static void main(String[] args) {
        Dog dog = new Dog("旺财");
        System.out.println("请" + dog.getName() + "叫三声");
        dog.speak();
        dog.speak();
        dog.speak();

        Duck duck = new Duck("一只平凡的鸭子");
        System.out.println("请" + duck.getName() + "叫三声");
        duck.speak();
        duck.speak();
        duck.speak();

        Cat cat = new Cat("小咪");
        System.out.println("请" + cat.getName() + "叫三声");
        cat.speak();
        cat.speak();
        cat.speak();
    }
}

运行上面代码时实现以下输出:

请旺财叫三声
汪汪
汪汪
汪汪
请一只平凡的鸭子叫三声
嘎嘎
嘎嘎
嘎嘎
请小咪叫三声
喵喵
喵喵
喵喵

允许对Main中的代码进行简化,以便减少重复代码。(提示:通过静态方法、继承和多态)

Dog类参考代码:

public class Dog {
    private final String name;

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void speak() {
        System.out.println("汪汪");
    }
}

简化猫狗鸭类

会发现猫狗鸭类里面有大量的重复代码!例如它们都有名字,很自然想到通过继承简化代码:

引入一个公共超类就可以把getName方法放在继承层次结构中更高的一层

例如,定义一个公共超类叫Animal(动物类),这样通过继承该类就可以自动获得name字段和getName方法!

public class Animal {
    private final String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Dog类改进版,参考代码:

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    public void speak() {
        System.out.println("汪汪");
    }
}

修改猫狗鸭类的实现之后,代码执行结果不变。

抽象方法、抽象类

为减少main方法中的重复代码,可以引入一个静态方法,借助Java中的多态与动态绑定机制简化代码

多态:一个对象变量可以指示多种实际类型;动态绑定:在运行时能够自动地选择合适的方法)

import java.util.ArrayList;

public class Main {
    public static void perform(Animal animal) {
        System.out.println("请" + animal.getName() + "叫三声");
        animal.speak();
        animal.speak();
        animal.speak();
    }

    public static void main(String[] args) {
        ArrayList<Animal> animals = new ArrayList<>();
        animals.add(new Dog("旺财"));
        animals.add(new Duck("一只平凡的鸭子"));
        animals.add(new Cat("小咪"));

        for (Animal animal : animals) {
            perform(animal);
        }
    }
}

为了让speak顺利调用必须在Animal类中也定义一个speak方法:

public class Animal {
    private final String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void speak() {
        System.out.println("???????");
    }
}

但需要注意到一个事实,概念上讲,我们并不知道动物是怎么叫的,而且,实际上我们永远不会调用animal中的speak方法,也就是说我们animal中的speak方法并没有实际意义。仅仅是为了Animal类的变量可以调用speak方法。针对这个问题,如何消除无用的代码?Java提供了一个叫做abstract的关键词,可以让我们不需要写无用代码。

public abstract class Animal {
    private final String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public abstract void speak();
}

为了提高程序的清晰性,包含一个或多个抽象方法的类本身必须被声明为抽象的。

抽象类相关规则

当定义一个抽象方法之后,包含这个抽象方法的类需要被声明为抽象类。

当扩展一个抽象类的时候,子类需要定义(抽象)超类中的所有抽象方法,否则就必须将子类也标记为抽象类。

假设去掉猫狗鸭类中的speak后,会发生什么?

练习:宠物商店管理系统 

public class PetShopTest {
    public static void main(String[] args) {
        // 创建宠物商店
        PetShop shop = new PetShop();

        // 添加宠物
        Dog dog = new Dog("Buddy", 3);
        Cat cat = new Cat("Kitty", 2);

        shop.addPet(dog);
        shop.addPet(cat);

        // 展示宠物
        shop.showPets();

        // 调用宠物行为
        System.out.println("=== 宠物行为 ===");
        dog.eat();
        dog.sit();

        cat.eat();
        cat.catchMouse();
    }
}

输出示例:

添加了一只宠物,名字:Buddy,年龄:3
添加了一只宠物,名字:Kitty,年龄:2
=== 宠物展示 ===
宠物名字:Buddy,年龄:3
Buddy 叫声:汪汪!
宠物名字:Kitty,年龄:2
Kitty 叫声:喵喵!
=== 宠物行为 ===
Buddy 在吃狗粮。
Buddy 表演了坐下。
Kitty 在吃猫粮。
Kitty 抓到了一只老鼠!

 

posted @ 2024-11-20 21:14  xkfx  阅读(184)  评论(0)    收藏  举报