继承(Inheritance) 是面向对象编程(OOP)的四大核心特性之一(其余为封装、多态、抽象),它允许一个类(子类)基于另一个类(父类)来构建,从而复用已有代码、扩展功能、建立类之间的层次关系

“继承 = 复用 + 扩展”
子类自动拥有父类的属性和方法,并可在此基础上添加新特性或修改已有行为。


一、继承的核心目的

  1. 代码复用:避免重复编写相同逻辑;
  2. 建立类间关系:体现“is-a”关系(如“狗 is a 动物”);
  3. 支持多态:为运行时多态提供基础(父类引用指向子类对象)。

二、Java 中如何实现继承?

1. 语法:使用 extends 关键字

class 父类 {
    // 父类成员
}

class 子类 extends 父类 {
    // 子类新增或重写的成员
}

2. 示例:动物 → 狗

// 父类
class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + " is eating.");
    }
}

// 子类
class Dog extends Animal {
    public Dog(String name) {
        super(name); // 调用父类构造器
    }

    // 新增方法
    public void bark() {
        System.out.println(name + " is barking!");
    }

    // 重写父类方法
    @Override
    public void eat() {
        System.out.println(name + " is eating dog food.");
    }
}

使用:

Dog dog = new Dog("旺财");
dog.eat();  // 输出:旺财 is eating dog food.
dog.bark(); // 输出:旺财 is barking!

三、继承的关键规则

✅ 1. Java 只支持单继承

  • 一个类只能直接继承一个父类(避免菱形继承问题);
  • 但可通过接口(interface)实现多继承效果
// ❌ 错误:Java 不允许多继承
// class A extends B, C { }

// ✅ 正确:通过接口
class A extends B implements C, D { }

✅ 2. 构造器不会被继承,但会调用

  • 子类构造器必须调用父类构造器(显式或隐式);
  • 若父类无无参构造器,子类必须显式调用 super(...)
class Parent {
    public Parent(String name) { }
}

class Child extends Parent {
    public Child() {
        super("default"); // 必须显式调用
    }
}

✅ 3. 成员访问权限影响继承

  • private 成员:子类不可见(但存在于对象中);
  • protected / public / 默认(包内):可被继承(受访问控制限制)。

📌 提示:通常将父类字段设为 protected,以便子类安全访问。

✅ 4. 方法可被重写(Override),字段不能

  • 子类可重写父类的非 private、非 final、非 static 方法;
  • 字段即使同名,也是隐藏(hiding),不是重写。
class Parent {
    int value = 10;
}

class Child extends Parent {
    int value = 20; // 隐藏父类字段,不是重写
}

四、super 关键字的作用

用法 说明
super() 调用父类构造器(必须在子类构造器第一行)
super.method() 调用父类被重写的方法
super.field 访问父类被隐藏的字段(不推荐,应避免字段隐藏)

示例:

@Override
public void eat() {
    super.eat(); // 先执行父类逻辑
    System.out.println("...and wagging tail.");
}

五、继承的适用场景与原则

✅ 适合使用继承的情况:

  • 存在明确的 “is-a” 关系(如 Student is a Person);
  • 子类确实是父类的特殊化
  • 需要复用并扩展父类行为。

❌ 不适合使用继承的情况:

  • 仅为复用代码而强行建立“is-a”关系(违反设计原则);
  • 类之间是 “has-a” 关系(应使用组合/聚合)。

🌰 例子:

  • Car 继承 Vehicle(汽车 is a 车辆)→ 合理;
  • Car 继承 Engine(汽车 has an 引擎)→ 应使用组合:class Car { private Engine engine; }

📜 里氏替换原则(LSP)

子类对象应当能够替换父类对象,且程序行为不变。
如果重写方法后破坏了父类契约,说明继承设计不合理。


六、继承 vs 组合(Composition)

对比项 继承 组合
关系 is-a has-a
耦合度 高(紧耦合) 低(松耦合)
灵活性 低(编译期确定) 高(运行时可变)
复用方式 代码继承 对象持有

💡 优先使用组合,而非继承(《Effective Java》建议)
组合更灵活、更安全,避免继承带来的脆弱基类问题。


七、总结:继承的价值与注意事项

✅ 优势:

  • 代码复用,减少冗余;
  • 建立清晰的类层次结构;
  • 为多态提供基础。

⚠️ 注意事项:

  1. 不要为了复用而滥用继承
  2. 遵循“is-a”原则和里氏替换原则
  3. 慎用继承,优先考虑组合
  4. 父类设计要稳定,否则影响所有子类;
  5. 避免深层继承链(如 A → B → C → D),增加维护难度。

🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐