1. 概述
继承作为面向对象编程的核心原则之一,让我们能够复用现有代码或扩展现有类型。
简单来说,在Java中:
- 类可以继承另一个类和多个接口
- 接口可以继承其他接口
本文将首先阐述继承的必要性,接着深入探讨类与接口的继承机制。然后分析变量/方法名称和访问修饰符如何影响成员继承,最后解释类型继承的实际意义。
2. 为什么需要继承
想象你作为汽车制造商,为客户提供多种车型。尽管不同车型可能有特殊功能(如天窗或防弹玻璃),但它们都包含基础组件(如发动机和车轮)。
与其为每个车型从头设计,不如创建基础设计并扩展出专业版本——这正是继承的核心思想。
通过继承,我们可以:
- 创建包含基础功能的基类
- 通过子类扩展出专业版本
- 接口同理,可扩展现有接口
术语对照:
- 基类型 = 超类/父类
- 派生类型 = 扩展类/子类
3. 类的继承
3.1. 扩展类
类可通过extends
关键字继承另一个类并定义新成员。先定义基类Car
:
public class Car {
int wheels;
String model;
void start() {
// 检查核心部件
}
}
子类ArmoredCar
继承Car
:
public class ArmoredCar extends Car {
int bulletProofWindows;
void remoteStartCar() {
// 通过遥控启动车辆
}
}
关键规则:
✅ Java类支持单继承(ArmoredCar
不能同时继承多个类)
✅ 未显式继承时,默认继承java.lang.Object
✅ 子类继承父类的:
protected
和public
成员- 同包下的
default
(包私有)成员 ❌ 不继承: private
成员static
成员
3.2. 子类访问父类成员
直接使用继承的成员即可,无需父类引用:
public class ArmoredCar extends Car {
public String registerModel() {
return model; // 直接访问父类字段
}
}
4. 接口继承
4.1. 实现多个接口
虽然类只能单继承,但可同时实现多个接口。假设为特工的ArmoredCar
添加飞行和漂浮功能:
public interface Floatable {
void floatOnWater();
}
public interface Flyable {
void fly();
}
public class ArmoredCar extends Car implements Floatable, Flyable {
public void floatOnWater() {
System.out.println("我能漂浮!");
}
public void fly() {
System.out.println("我能飞行!");
}
}
注意使用implements
关键字实现接口。
4.2. 多继承的坑
Java通过接口支持多继承,但需注意:
Java 7之前:接口只能定义抽象方法,同名方法签名无冲突。
Java 8+的陷阱:接口可定义default
方法实现。当实现多个含相同方法签名的接口时:
public interface Floatable {
default void repair() {
System.out.println("维修漂浮设备");
}
}
public interface Flyable {
default void repair() {
System.out.println("维修飞行设备");
}
}
public class ArmoredCar extends Car implements Floatable, Flyable {
// 编译失败!必须重写repair()
}
⚠️ 解决方案:显式重写冲突方法。
同名常量冲突:
public interface Floatable {
int duration = 10;
}
public interface Flyable {
int duration = 20;
}
public class ArmoredCar extends Car implements Floatable, Flyable {
public void aMethod() {
// System.out.println(duration); // 编译错误
System.out.println(Floatable.duration); // 输出10
System.out.println(Flyable.duration); // 输出20
}
}
4.3. 接口继承接口
接口可继承多个接口(使用extends
关键字):
public interface Floatable {
void floatOnWater();
}
public interface Flyable {
void fly();
}
public interface SpaceTraveller extends Floatable, Flyable {
void remoteControl();
}
区别:类用
implements
实现接口,接口用extends
继承接口。
5. 类型继承
继承不仅传递成员,还传递类型。这让我们能面向接口/基类编程,而非具体实现。
例如,公司维护员工车辆列表(车型各异):
public class Employee {
private String name;
private Car car; // 使用基类类型
// 标准构造器
}
所有Car
子类都继承Car
类型,因此可用基类引用指向子类实例:
Employee e1 = new Employee("张伟", new ArmoredCar());
Employee e2 = new Employee("李娜", new SpaceCar());
Employee e3 = new Employee("王芳", new BMW());
6. 成员隐藏
6.1. 实例成员隐藏
当父子类存在同名变量/方法时:
public class ArmoredCar extends Car {
private String model;
public String getAValue() {
return super.model; // 返回父类Car的model
// return this.model; // 返回ArmoredCar的model
// return model; // 默认返回ArmoredCar的model
}
}
技巧:用
super
明确访问父类成员,this
访问当前类成员。
6.2. 静态成员隐藏
静态成员属于类而非实例,处理方式不同:
public class Car {
public static String msg() {
return "Car";
}
}
public class ArmoredCar extends Car {
public static String msg() {
return super.msg(); // 编译错误!静态方法中不能用super
}
}
正确姿势:
return Car.msg(); // 通过类名调用
同名静态方法调用示例:
Car first = new ArmoredCar();
ArmoredCar second = new ArmoredCar();
first.msg(); // 输出"Car"(变量类型决定)
second.msg(); // 输出"ArmoredCar"(实际类型决定)
本质:静态方法调用取决于引用变量的声明类型。
7. 总结
本文深入探讨了Java继承的核心机制:
- 类支持单继承,接口支持多继承
- 继承传递成员和类型
- 成员隐藏规则需特别注意(静态/实例差异)
- 多继承场景需处理方法冲突
掌握这些概念能帮你写出更灵活的代码,避免常见陷阱。完整示例代码见GitHub仓库。