继承与接口的比较
继承
- 核心关系: “is-a”(是一种)关系。子类是父类的一种更具体的类型(例如:Car is-a Vehicle)。
- 实现方式: 使用 extends 关键字来声明继承关系,例如 class Child extends Parent。
- 继承内容: 子类自动继承父类所有非 private 的成员变量和成员方法,可以直接使用。
- 不继承内容: 构造方法和被 private 修饰的成员不能被子类直接继承或访问。
- 构造方法规则: 子类的构造方法第一行必须调用父类的构造方法或本类的另一个构造方法 this(…)。如果未显式使用 super(…) 调用,编译器会自动添加一个无参的 super()。如果父类没有无参构造方法,子类必须在其所有构造方法中显式调用父类的有参构造方法。
- 方法重写 (Overriding): 子类可以提供一个与父类方法签名(方法名、参数列表)完全相同的新实现来覆盖父类的行为。建议使用 @Override 注解进行标记。
- 重写规则: 重写的方法访问权限不能比父类更严格,返回类型必须相同或者是父类返回类型的子类。
- 成员变量隐藏 (Hiding): 成员变量只能被隐藏,不能被重写。当子类定义了与父类同名的变量时,具体访问哪个变量取决于引用的类型,而不是对象的实际类型。
- super 关键字: 在子类中,使用 super.成员 来访问父类中被隐藏的变量或被重写的方法;使用 super() 来调用父类的构造方法。
- 多态 (Polymorphism): 父类的引用可以指向子类的对象(Parent p = new Child();),这被称为向上转型。
- 多态表现: 当通过父类引用调用一个被重写的方法时,实际执行的是子类中的方法版本。
- 向下转型 (Downcasting): 将父类引用强制转换回子类引用(Child c = (Child) p;),这存在 ClassCastException 的风险。
- instanceof 关键字: 在进行向下转型之前,应使用 instanceof 关键字检查引用的实际对象类型,以确保类型安全,避免异常。
- final 关键字: 被 final 修饰的类不能被继承;被 final 修饰的方法不能被子类重写。
- 单继承原则: Java 只支持单继承,即一个类最多只能有一个直接父类,但可以通过实现多个接口来弥补。
抽象父类的继承
- 核心关系: 既是 “is-a” 关系,又是一种不完整的设计模板。它代表一个抽象的概念,其本身不能被完整地实现。
- 声明方式: 类本身必须使用 abstract 关键字声明。类中可以包含抽象方法,也必须用 abstract 声明且没有方法体。
- 不可实例化: 不能使用 new 关键字直接创建抽象类的实例,因为它是不完整的。
- 成员构成: 抽象类是普通类和接口的混合体,它可以包含成员变量、常量、构造方法、具体方法和抽象方法。
- 强制规则: 任何包含一个或多个抽象方法的类,必须被声明为抽象类。但抽象类可以不包含任何抽象方法。
- 子类责任: 继承抽象类的具体子类必须实现(重写)父类中所有的抽象方法。如果子类不想全部实现,那么该子类也必须被声明为抽象类。
- 构造方法用途: 抽象类可以有构造方法,其唯一目的是为了被子类的构造方法通过 super() 调用,以初始化从父类继承来的成员变量。
- 核心用途: 完美地结合了代码复用和行为规范。它为所有子类提供公共的状态和行为(通过成员变量和具体方法),同时强制它们必须实现某些特定的行为(通过抽象方法)。
接口
- 核心关系: “can-do”(能做什么)或行为契约。接口定义了一组类必须遵守的规范或能力,强调“能做什么”,而不是“是什么”。
- 实现方式: 使用 implements 关键字来实现一个或多个接口,例如 class MyClass implements MyInterface。
- 多实现: 一个类可以同时实现多个接口,从而获得多种不同的能力。这是 Java 实现“类多重继承”效果的方式。
- 实现承诺: 实现类必须为接口中所有的抽象方法提供具体实现(方法体)。如果未能全部实现,该类必须被声明为抽象类 (abstract class)。
- 抽象方法: 接口中的方法默认是 public abstract 的,没有方法体。实现类在重写时必须使用 public 访问修饰符。
- 常量: 接口中声明的任何变量都默认是 public static final 的,即全局常量,必须在声明时初始化。
- 默认方法 (Default Methods - Java 8+): 使用 default 关键字,接口可以提供方法的默认实现。实现类可以选择直接继承使用,也可以重写它。
- 静态方法 (Static Methods - Java 8+): 接口可以包含 static 方法。这些方法只能通过 接口名.方法名() 的方式调用,不能被实现类继承或重写。
- 多态应用: 接口引用可以指向其任何实现类的对象(MyInterface ref = new MyClass();),这是实现多态和程序解耦的关键。
- 不可实例化: 接口不能被直接实例化(不能使用 new 关键字创建接口自身的实例)。
- 接口间的继承: 一个接口可以使用 extends 关键字继承一个或多个其他接口,从而将父接口的所有成员合并到自身。
- 默认方法冲突: 如果一个类实现的多个接口中包含签名相同的默认方法,该类必须重写此方法以解决冲突。
- 无状态与构造方法: 接口没有成员变量(只有常量)和构造方法。它只定义行为,不关心状态的存储。