103. Java 继承 - 状态、实现和类型的多重继承
在 Java 中,类和接口之间有几个显著的区别。类可以包含字段(即实例变量),而接口不能。此外,可以实例化一个类来创建对象,而接口不能直接实例化对象。对象的状态存储在类的字段中,这些字段定义在类中。Java
编程语言不允许从多个类继承的一个原因是为了避免"状态的多重继承"问题,即从多个类继承字段的问题。我们来具体了解一下这几个概念。
状态的多重继承
假设 Java
允许多继承,可以定义一个类继承自多个类。如果我们通过实例化该类来创建一个对象,这个对象会从所有父类继承字段。如果父类的字段或方法有冲突,编译器将无法确定使用哪个字段或方法。
例如,假设我们有以下类:
java
class A {
String name = "Class A";
}
class B {
String name = "Class B";
}
class C extends A, B { // 假设 Java 允许多继承
// 问题:name 字段来自 A 和 B,编译器不知道该使用哪个字段
}
如果 C
类继承了 A
和 B
,这就会引发"状态的多重继承"问题:A
和 B
都定义了 name
字段,C
类无法确定应使用哪个字段。
然而,在 Java
中,类不允许多继承,因此避免了这种问题。接口不包含字段,所以不必担心这种类型的冲突。
实现的多重继承
实现的多重继承指的是类继承多个类的方法定义的能力。在 Java
中,我们通常使用接口来实现多继承。但是,多个接口可能定义同名的方法,这会导致一些问题,例如名称冲突和歧义。
java
interface Interface1 {
default void show() {
System.out.println("Interface1 method");
}
}
interface Interface2 {
default void show() {
System.out.println("Interface2 method");
}
}
class MyClass implements Interface1, Interface2 {
@Override
public void show() {
// 冲突:继承了两个接口的同名方法
System.out.println("MyClass method");
}
}
在上面的例子中,Interface1
和 Interface2
都有一个默认方法 show()
。当 MyClass
实现这两个接口时,它会面临方法冲突,因为两个接口都定义了同名方法 show()
。
Java
通过引入 默认方法 来支持接口的多重继承。默认方法是接口中定义的具有实现的方法,它可以被实现类直接使用,但如果有冲突,类需要显式地覆盖它们。上述代码中,MyClass
需要通过重写 show()
方法来解决冲突。
类型的多重继承
Java
支持接口的多重继承,也就是说一个类可以实现多个接口,允许对象具有多种类型。一个对象不仅有自己的类类型,还有它实现的所有接口的类型。
例如:
java
interface Movable {
void move();
}
interface Runnable {
void run();
}
class Robot implements Movable, Runnable {
@Override
public void move() {
System.out.println("Robot is moving");
}
@Override
public void run() {
System.out.println("Robot is running");
}
}
public class Main {
public static void main(String[] args) {
Robot robot = new Robot();
robot.move(); // 输出:Robot is moving
robot.run(); // 输出:Robot is running
// 通过接口类型声明
Movable movable = robot;
movable.move(); // 输出:Robot is moving
Runnable runnable = robot;
runnable.run(); // 输出:Robot is running
}
}
在这个例子中,Robot
类实现了两个接口:Movable
和 Runnable
。这样,Robot
类对象不仅是 Robot
类型的对象,它还是 Movable
类型和 Runnable
类型的对象。通过接口类型声明的变量可以引用实现了这些接口的类的对象。
总结
- 状态的多重继承:Java 不允许类多继承,避免了从多个类继承字段的潜在冲突。
- 实现的多重继承:Java 允许类实现多个接口,这些接口可以包含默认方法,但如果接口方法冲突,类必须覆盖这些方法。
- 类型的多重继承:一个类可以实现多个接口,从而使对象具备多种类型。这种多重继承不会引发状态的冲突,因为接口不包含字段。
- 默认方法冲突:Java 允许接口提供默认方法,但如果实现类继承了多个接口,并且这些接口有相同名称的默认方法,编译器会要求类显式覆盖这些方法。