目录

一、核心定义与设计思想

1. 核心定义

2. 核心设计思想

3. 继承的核心规则(必记)

4. 访问权限与继承(核心)

二、底层实现原理(含 JDK 源码 / 反编译验证)

1. 类加载与初始化底层(执行顺序)

2. 内存模型

3. 方法重写底层:动态绑定

4. 反编译验证(默认 super () 调用)

5. JDK 源码中的继承典范

三、代码示例

1. 基础继承 + 方法重写 + super 用法(标准示例)

2. 执行顺序验证示例

四、高频踩坑点与避坑方案

坑点 1:子类继承父类私有成员(误区)

坑点 2:子类构造方法未调用父类构造

坑点 3:方法重写违反规则(编译报错)

坑点 4:滥用继承,导致代码强耦合

坑点 5:混淆 super 和 this

坑点 6:成员变量隐藏

五、面试高频考点与标准答案

1. 什么是继承?继承的作用是什么?

2. Java 为什么只能单继承?

3. super 和 this 的区别?

4. 方法重写(Override)和重载(Overload)的区别?

5. 子类对象初始化的执行顺序?

6. 私有成员能被继承吗?构造方法能被继承吗?

六、项目改造 / 落地记录

核心设计原则:组合优于继承(企业开发第一准则)

1. 改造前(滥用继承,强耦合,严禁使用)

2. 改造后(合理继承 + 组合优先)

场景 1:合理继承(满足 is-a 关系)

场景 2:组合替代继承(推荐)

3. 改造落地好处

总结


一、核心定义与设计思想

1. 核心定义

继承(Inheritance) 是面向对象三大特性之一,使用 extends 关键字实现:

  • 允许一个类(子类 / 派生类)复用另一个类(父类 / 基类 / 超类)的非私有属性和方法
  • 子类可以在父类基础上扩展新功能,或重写(Override) 父类原有方法;
  • Java 规定:类只能单继承,支持多层继承,接口可多实现。

2. 核心设计思想

  1. 代码复用:抽取多个类的公共属性 / 方法到父类,避免重复代码;
  2. 层级抽象:构建类的层级关系,符合现实世界逻辑(如 Person → Student → CollegeStudent);
  3. 多态基础:继承是多态的前提(没有继承就没有方法重写,就没有多态);
  4. 功能扩展:不修改父类,仅通过子类扩展功能,符合开闭原则

3. 继承的核心规则(必记)

  1. 单继承:一个子类只能有一个直接父类(Java 禁止类多继承,避免菱形问题);
  2. 多层继承:支持链式继承(A→B→C);
  3. 权限限制:子类不能继承父类私有成员private 变量 / 方法);
  4. 构造方法:子类不能继承父类构造方法,只能通过 super() 调用;
  5. 所有类默认继承java.lang.Object 是所有类的顶级父类。

4. 访问权限与继承(核心)

修饰符本类同包子类任意类能否被继承
private❌ 不能
默认(包)✅ 同包子类
protected✅ 全包子类
public✅ 可以

二、底层实现原理(含 JDK 源码 / 反编译验证)

1. 类加载与初始化底层(执行顺序)

子类对象创建时,JVM 严格执行父类优先机制:

  1. 加载子类 → 先加载父类(递归至 Object);
  2. 父类静态代码块 → 子类静态代码块;
  3. 父类构造代码块 → 父类构造方法;
  4. 子类构造代码块 → 子类构造方法。

2. 内存模型

子类对象在堆内存中,会完整包含父类对象的实例

  • 子类对象 = 子类独有成员 + 父类继承的成员;
  • super 关键字本质:指向子类对象中父类部分的引用

3. 方法重写底层:动态绑定

  • 静态方法:编译期绑定(静态绑定),不存在重写;
  • 实例方法:运行期绑定(动态绑定),JVM 根据实际对象类型调用重写后的方法。

4. 反编译验证(默认 super () 调用)

测试代码:

class Parent {}
class Child extends Parent {
    public Child() {}
}

反编译命令:javap -c Child核心字节码

0: aload_0
1: invokespecial #1 // Method Parent."<init>":()V 

 结论:子类构造方法默认第一行隐藏 super(),强制调用父类无参构造。

5. JDK 源码中的继承典范

// AbstractList 封装了List的公共逻辑
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}

// ArrayList 复用AbstractList,仅实现独有功能
public class ArrayList<E> extends AbstractList<E> implements List<E> {}

三、代码示例

1. 基础继承 + 方法重写 + super 用法(标准示例)

// 父类:抽取公共属性和方法
class Person {
    protected String name;
    protected int age;

    // 父类构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 公共方法
    public void showInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
}

// 子类:继承Person,扩展功能
class Student extends Person {
    private String studentId; // 子类独有属性

    // 子类构造:必须先调用父类构造
    public Student(String name, int age, String studentId) {
        super(name, age); // 调用父类有参构造(必须在第一行)
        this.studentId = studentId;
    }

    // 方法重写:Override 父类方法
    @Override
    public void showInfo() {
        super.showInfo(); // 调用父类原有方法
        System.out.println("学号:" + studentId); // 扩展功能
    }
}

// 测试
public class ExtendsDemo {
    public static void main(String[] args) {
        Student student = new Student("张三", 20, "S1001");
        student.showInfo();
    }
}

2. 执行顺序验证示例

class Parent {
    static { System.out.println("父类静态代码块"); }
    { System.out.println("父类构造代码块"); }
    public Parent() { System.out.println("父类构造方法"); }
}

class Child extends Parent {
    static { System.out.println("子类静态代码块"); }
    { System.out.println("子类构造代码块"); }
    public Child() { System.out.println("子类构造方法"); }
}

// 输出结果:严格遵循 父静态→子静态→父构造块→父构造→子构造块→子构造

四、高频踩坑点与避坑方案

坑点 1:子类继承父类私有成员(误区)

  • 问题:误以为 private 变量 / 方法能被继承;
  • 真相:private 成员属于父类私有,子类无法访问、无法继承
  • 避坑:父类私有属性通过 public/protectedgetter/setter 访问。

坑点 2:子类构造方法未调用父类构造

  • 问题:父类无无参构造,子类编译报错;
  • 原因:子类默认调用 super(),父类无无参构造时必须手动写 super(参数)
  • 避坑:父类提供无参构造,或子类手动调用有参构造。

坑点 3:方法重写违反规则(编译报错)

重写强制规则

  1. 方法名、参数列表、返回值(协变)必须完全一致;
  2. 子类方法权限不能小于父类(父类public,子类不能写private);
  3. 子类异常不能大于父类;
  4. 静态方法不能重写(只能隐藏)。

坑点 4:滥用继承,导致代码强耦合

  • 问题:为了复用代码随意继承,破坏类的关系(如 Dog extends Car);
  • 原则:继承必须满足 is-a 关系(Student is a Person);
  • 避坑:组合优于继承(优先用包含关系复用代码)。

坑点 5:混淆 superthis

  • 问题:super() 不写在第一行,编译报错;
  • 规则:super()/this() 必须在构造方法第一行,且不能同时存在。

坑点 6:成员变量隐藏

  • 问题:子类和父类定义同名变量,子类覆盖父类变量;
  • 避坑:尽量避免同名成员变量,必须使用时用 super.变量 区分。

五、面试高频考点与标准答案

1. 什么是继承?继承的作用是什么?

标准答案:继承是子类使用 extends 复用父类非私有成员的机制;作用:代码复用、层级抽象、扩展功能、是多态的前提

2. Java 为什么只能单继承?

标准答案:为了避免菱形问题(钻石问题):多个父类有同名方法,子类无法确定调用哪个;Java 类单继承,接口支持多实现,兼顾安全与灵活。

3. superthis 的区别?

标准答案

  1. this:指向当前对象,访问本类成员;
  2. super:指向父类对象,访问父类成员;
  3. 都必须在构造方法第一行,不能同时使用;
  4. this 可单独使用,super 依赖继承。

4. 方法重写(Override)和重载(Overload)的区别?

标准答案

特性重写(Override)重载(Overload)
位置父子类中同一个类中
参数列表必须相同必须不同
权限不能缩小无限制
多态运行期多态编译期无多态

5. 子类对象初始化的执行顺序?

标准答案:父类静态代码块 → 子类静态代码块 → 父类构造代码块 → 父类构造方法 → 子类构造代码块 → 子类构造方法。

6. 私有成员能被继承吗?构造方法能被继承吗?

标准答案

  1. private 成员不能被继承
  2. 构造方法不能被继承,只能通过 super() 调用。

六、项目改造 / 落地记录

核心设计原则:组合优于继承(企业开发第一准则)

1. 改造前(滥用继承,强耦合,严禁使用)

// 错误:为了复用代码,强行继承(Dog不是Car)
class Car {
    public void run(){}
}
class Dog extends Car {
    // 逻辑混乱,耦合度极高
}

2. 改造后(合理继承 + 组合优先)

场景 1:合理继承(满足 is-a 关系)
// 父类:公共业务实体
public class BaseEntity {
    protected Long id;
    protected Date createTime;
    protected Date updateTime;
}

// 子类:业务实体继承父类,复用公共字段
public class User extends BaseEntity {
    private String username;
}
public class Order extends BaseEntity {
    private String orderNo;
}
场景 2:组合替代继承(推荐)
// 工具类
class RunUtils {
    public void run(){}
}

// 组合:包含工具类对象,复用功能
class Dog {
    private RunUtils runUtils = new RunUtils();
    public void run() {
        runUtils.run();
    }
}

3. 改造落地好处

  1. 低耦合:组合不依赖继承关系,修改父类不影响子类;
  2. 逻辑清晰:仅 is-a 关系使用继承,符合业务语义;
  3. 易维护:公共属性抽取到父类,统一管理;
  4. 符合规范:遵循阿里 Java 开发手册,避免滥用继承。

总结

  1. 核心本质:继承 = extends + 代码复用 + 扩展功能,Java 类单继承,必须满足 is-a 关系;
  2. 底层关键:子类对象包含父类实例,初始化父类优先,方法重写是动态绑定;
  3. 避坑铁律:私有成员 / 构造方法不能继承,重写遵守权限规则,组合优于继承
  4. 实战规范:公共属性 / 方法抽取父类,业务无关类用组合复用代码,禁止滥用继承。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐