接口弥补多继承缺失
- 原理:接口定义了一组方法的签名,但没有方法的实现。一个类可以实现多个接口,从而获得多个接口定义的行为。这使得类能从多个来源获取不同的行为定义,模拟多继承。例如:
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("Bird is flying");
}
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck is flying");
}
@Override
public void swim() {
System.out.println("Duck is swimming");
}
}
- 优势:
- 灵活性高:接口只定义行为,不关心实现细节,一个类可以根据自身需求灵活选择实现哪些接口。
- 解耦性强:接口使用者和实现者之间松耦合,便于系统的扩展和维护。例如,若要给某个类添加新行为,只需让它实现新接口即可。
- 有利于代码复用:不同类可以实现相同接口,复用接口定义的行为。
- 局限:
- 接口不能有状态:接口中只能定义常量,不能有实例变量,这限制了接口对对象状态的维护。
- 实现复杂:当实现多个接口时,如果接口间方法签名冲突,处理起来较为复杂。例如多个接口定义了同名方法,实现类需统一处理。
抽象类弥补多继承缺失
- 原理:抽象类可以包含抽象方法和具体方法,抽象方法只有声明没有实现,具体方法有方法体。一个类只能继承一个抽象类,但可以从抽象类继承部分行为和属性,通过多层继承,可在一定程度模拟多继承。例如:
abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public abstract void move();
}
abstract class FlyingAnimal extends Animal {
public FlyingAnimal(String name) {
super(name);
}
public void fly() {
System.out.println(name + " is flying");
}
}
class Bird extends FlyingAnimal {
public Bird(String name) {
super(name);
}
@Override
public void move() {
fly();
}
}
- 优势:
- 可包含状态和行为:抽象类可以有成员变量和具体方法,能为子类提供一些通用的状态和行为实现,减少子类重复代码。
- 代码结构清晰:通过继承抽象类,类的层次结构更加清晰,便于理解和维护。例如,动物相关类通过继承抽象的
Animal
类,结构清晰。
- 局限:
- 单继承限制:Java 中一个类只能继承一个抽象类,无法像多继承那样同时从多个父类获取行为和属性。
- 灵活性较差:子类对抽象类的继承较为紧密,一旦继承,受抽象类的约束较大,不利于灵活扩展。例如,子类很难在不改变继承体系下,增加其他来源的行为。