时间:2023-04-14
标签: #Java #多态 #接口 #抽象类 #设计
当我们已经有多态这一机制了之后,为什么还有 implements 这一设计呢?直接设计一个最上层的父类然后设计很多需要子类实现的抽象方法不就好了么?如果这样的方式不是多态的目的,那么抽象方法本身存在的意义又是什么呢?能否同时举例说明上述问题?
多态是一种编程范式,它允许我们使用一个通用的接口引用不同类型的对象,并在运行时动态调用相应的方法。接口和抽象类都是实现多态的方式,但它们有不同的用途和特点。
- 接口(implements):
接口定义了一组规范,强调了类实现的“能做什么”。接口可以被多个类实现,这样可以实现多重继承的效果。当一个类实现了一个接口时,它承诺实现接口中定义的所有方法。这对于定义一些通用的行为和功能非常有用。接口还允许我们将实现和使用分离,使代码更加灵活和易于维护。
- 抽象类(extends):
抽象类是一个特殊的类,它不能被实例化,只能被继承。抽象类中可以包含抽象方法和非抽象方法。抽象方法没有具体的实现,需要子类去实现。抽象类强调类之间的“是什么”关系,即子类“是一种”父类。抽象类适用于在类之间共享部分实现的情况。
以下是一个举例说明:
// 接口:表示可飞行的对象
public interface Flyable {
void fly();
}
// 抽象类:表示鸟类,包含共享的属性和方法
public abstract class Bird {
private String name;
public Bird(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
public abstract void sing(); // 抽象方法
}
// 具体类:鹦鹉,继承自Bird类,实现Flyable接口
public class Parrot extends Bird implements Flyable {
public Parrot(String name) {
super(name);
}
@Override
public void fly() {
System.out.println("Parrot is flying.");
}
@Override
public void sing() {
System.out.println("Parrot is singing.");
}
}
在这个例子中,我们定义了一个 Flyable
接口和一个 Bird
抽象类。Parrot
类继承了 Bird
类,并实现了 Flyable
接口。这样,我们可以使用多态的特性,将 Parrot
类的对象赋值给 Bird
类型或 Flyable
类型的引用,并在运行时动态调用相应的方法。
总之,接口和抽象类都是实现多态的方式,但它们有不同的目的和使用场景。接口强调行为和功能,适用于定义通用的规范;抽象类强调类之间的关系,适用于在类之间共享部分实现。在实际的软件设计中,我们通常根据需求选择合适的方式来实现多态。
对于你提到的“为什么还有implements这一设计”的问题,这是因为Java不支持多重继承,即一个类不能继承多个父类。通过接口,我们可以实现类似多重继承的效果。接口允许我们定义一组行为,并可以被多个类实现,使得代码更加灵活和模块化。
关于抽象方法的存在意义,抽象方法强制子类去实现某些特定的行为。当我们定义一个抽象类时,我们可以预见到子类需要实现某些共同的行为,但这些行为的具体实现可能因子类而异。通过抽象方法,我们可以确保所有的子类都会实现这些行为,而不需要在每个子类中重复编写相同的代码。
例如,在上述的例子中,Bird
抽象类中的 sing
方法是一个抽象方法。这表示所有继承自 Bird
的子类都必须实现 sing
方法,以确保它们都具有唱歌的行为。这样,我们可以在处理 Bird
类型的对象时,确保它们都可以调用 sing
方法,而不需要关心具体的实现细节。