抽象类_演练
原始代码
定义一个鸭子类(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 抓到了一只老鼠!