Java继承详解:从零开始理解“父子关系”编程

目录

一、继承

[1.1 生活中的继承](#1.1 生活中的继承)

[1.2 继承的作用](#1.2 继承的作用)

二、继承的基本语法

[2.1 创建人员管理系统](#2.1 创建人员管理系统)

三、super关键字

[3.1 调用父类的方法](#3.1 调用父类的方法)

[3.2 带参数的构造方法调用](#3.2 带参数的构造方法调用)

[3.3 访问父类的属性(当父子有同名属性时)](#3.3 访问父类的属性(当父子有同名属性时))

[3.4 总结](#3.4 总结)

[规则 1:super() 必须是构造方法的第一条语句](#规则 1:super() 必须是构造方法的第一条语句)

[规则 2:super 只能在实例上下文中使用](#规则 2:super 只能在实例上下文中使用)

[规则 3:super.字段 仅在"字段遮蔽"时有意义](#规则 3:super.字段 仅在“字段遮蔽”时有意义)

[规则 4:super 不是引用变量,不能单独使用](#规则 4:super 不是引用变量,不能单独使用)

第四章:继承中的构造方法

[4.1 构造方法的调用顺序](#4.1 构造方法的调用顺序)

[第 1 步:C c1 = new C();(创建 C 的无参对象)](#第 1 步:C c1 = new C();(创建 C 的无参对象))

[第 2 步:C c2 = new C("Hello");(带一个参数)](#第 2 步:C c2 = new C("Hello");(带一个参数))

[第 3 步:C c3 = new C("Hello", "World");(两个参数)](#第 3 步:C c3 = new C("Hello", "World");(两个参数))

[第 4 步:B b = new B("测试B")](#第 4 步:B b = new B("测试B"))

[第 5 步:A a = new A("测试A")](#第 5 步:A a = new A("测试A"))

[4.2 打个比方(帮助记忆)](#4.2 打个比方(帮助记忆))

[4.3 总结:核心规律](#4.3 总结:核心规律)


一、继承

1.1 生活中的继承

在现实生活中:

  • 你继承了你父母的血脉
  • 你继承了你父母的姓氏
  • 你继承了你父母的家产
  • 你继承了父母的某些外貌特征

在编程世界中:

  • 一个类(子类)可以继承另一个类(父类)的特征
  • 子类自动拥有父类的属性和方法
  • 子类还可以添加自己独有的属性和方法
  • 子类可以修改从父类继承的行为

1.2 继承的作用

我们在学习继承之前肯定有所疑问,继承有什么用,难道在编程世界中也有家族继承这一类的事情发生吗?

那么我们来看看下面这个例子,我们来做一个非常简单的动物园系统:

我们先创建三个文件来存放三个类,Zoo为测试类,文件结构如下:

java 复制代码
//dog类
public class Dog {
    String name;
    int age;

    void eat() {
        System.out.println(name + "吃东西");
    }
    void sleep() {
        System.out.println(name + "在睡觉");
    }
    void bark(){
        System.out.println(name + "在旺旺叫");
    }
}
java 复制代码
//cat类
public class Cat {
    String name;
    int age;

    void eat() {
        System.out.println(name + "吃东西");
    }
    void sleep() {
        System.out.println(name + "在睡觉");
    }
    void meow(){
        System.out.println(name + "在喵喵叫");
    }
}
java 复制代码
//bird类
public class Bird {
    String name;
    int age;

    void eat() {
        System.out.println(name + "正在吃东西");
    }

    void sleep() {
        System.out.println(name + "正在睡觉");
    }

    void fly() {
        System.out.println("飞起来了!");
    }
}

首先我们会发现,我们给各个类都定义了两个成员变量,然后各自定义两个相同的成员方法,但是最后一个方法是各个动物所独有的,那么我们在测试类想要去访问他们的所有成员变量方法就会像下面的代码一样:

java 复制代码
//Zoo测试类
public class Zoo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "小黄";
        dog.age = 1;

        Cat cat = new Cat();
        cat.name = "小白";
        cat.age = 2;
        
        Bird bird = new Bird();
        bird.name = "鸟";
        bird.age = 3;
        
        System.out.println("狗的行为:");
        dog.eat();
        dog.sleep();
        dog.bark();//Dog独有方法

        System.out.println("猫的行为");
        cat.eat();
        cat.sleep();
        cat.meow();//Cat独有方法

        System.out.println("鸟的行为");
        bird.eat();
        bird.sleep();
        bird.fly();//Bird独有方法
    }
}

那么我们现在需要访问一下三个类的所有行为,我们运行一下我们的测试类:

复制代码

我们发现确实成功访问了我们的所有方法,但是大家再看看我们的Zoo测试类,我嘛会发现很多动物的方法是一样的呀 ,只有最后一个是不同的,其实大家结合为一开始给出的生活中的例子就能想到,**前三个共同有的方法不就是他们身为动物的共性吗?**那么这个时候我们来使用继承的方法给Zoo类优化一下:

我们来创建一个父类(Animal),这个类定义了所有动物的共同特征

我们再把动物类的内容给修改一下,只存放他们各自所独有的,所以文件结构如下:

java 复制代码
public class Animal {
    // 所有动物都有名字
    String name;

    // 所有动物都有年龄
    int age;

    // 所有动物都会吃东西(共同行为)
    void eat() {
        System.out.println(name + "正在吃东西");
    }

    // 所有动物都会睡觉(共同行为)
    void sleep() {
        System.out.println(name + "正在睡觉");
    }
}
java 复制代码
//Dog
public class Dog extends Animal {
    // extends Animal 表示 Dog 继承 Animal
    // Dog 是 Animal 的一种特殊类型
    String breed;  // 品种

    // 狗特有的方法
    void bark() {
        System.out.println(name + "汪汪叫!");
    }
}
java 复制代码
//Cat
public class Cat extends Animal {
    // 猫特有的属性
    String color;  // 颜色

    // 猫特有的方法
    void meow() {
        System.out.println(name + "喵喵叫!");
    }
}
java 复制代码
//Bird
public class Bird extends Animal {
    // 鸟特有的属性
    boolean canFly;  // 是否会飞

    // 鸟特有的方法
    void fly() {
        if (canFly) {
            System.out.println(name + "飞起来了!");
        } else {
            System.out.println(name + "不会飞");
        }
    }
}

那么我们这个时候,就会发现我们的动物类的代码会简洁很多,因为共性全部存放在了我们的父类

这个时候我们和之前的测试类一样,来尝试一下访问子类各自的特有成员方法:

java 复制代码
//Zoo测试类
public class Zoo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "小黑";  // 继承自Animal的属性
        dog.age = 3;        // 继承自Animal的属性
        dog.breed = "拉布拉多";  // Dog自己的属性

        // 创建猫对象
        Cat cat = new Cat();
        cat.name = "小花";  // 继承自Animal的属性
        cat.age = 2;        // 继承自Animal的属性
        cat.color = "白色";   // Cat自己的属性

        // 创建鸟对象
        Bird bird = new Bird();
        bird.name = "小黄";    // 继承自Animal的属性
        bird.age = 1;         // 继承自Animal的属性
        bird.canFly = true;   // Bird自己的属性

        // 显示所有动物的信息
        System.out.println("=== 狗的信息 ===");
        dog.eat();     // 继承自Animal的方法
        dog.sleep();   // 继承自Animal的方法
        dog.bark();    // Dog自己的方法

        System.out.println("\n=== 猫的信息 ===");
        cat.eat();     // 继承自Animal的方法
        cat.sleep();   // 继承自Animal的方法
        cat.meow();    // Cat自己的方法

        System.out.println("\n=== 鸟的信息 ===");
        bird.eat();     // 继承自Animal的方法
        bird.sleep();   // 继承自Animal的方法
        bird.fly();     // Bird自己的方法
    }
}

这个时候我们运行一下:

对比一下:

  • 代码量减少:共同代码只写一次

  • 维护更容易:修改共同功能只需修改Animal类

  • 结构更清晰:类之间的关系一目了然

二、继承的基本语法

2.1 创建人员管理系统

为了代码的健硕性,我把getter和setter都写了,但是大家主要看各类的独有方法和父类的共有方法就行

让我们创建一个更实用的例子:人员管理系统。

java 复制代码
//Employee类
public class Employee extends Person {
    // 员工特有的属性
    private String employeeId;     // 员工编号
    private String company;        // 公司
    private String department;     // 部门
    private String position;       // 职位
    private double salary;         // 工资

    // 构造方法
    public Employee(String name, int age, String gender, String idCard,
                    String employeeId, String company, String department,
                    String position, double salary) {
        // 调用父类的构造方法
        super(name, age, gender, idCard);

        // 设置员工特有的属性
        this.employeeId = employeeId;
        this.company = company;
        this.department = department;
        this.position = position;
        this.salary = salary;
    }

    // Getter方法

    public String getEmployeeId() {
        return employeeId;
    }

    public String getCompany() {
        return company;
    }

    public String getDepartment() {
        return department;
    }

    public String getPosition() {
        return position;
    }

    public double getSalary() {
        return salary;
    }

    // Setter方法

    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public void setSalary(double salary) {
        if (salary >= 0) {
            this.salary = salary;
        } else {
            System.out.println("工资不能为负数");
        }
    }

    // 员工特有的方法
    public void attendMeeting() {
        System.out.println(getName() + "正在参加会议");
    }

    public void submitReport() {
        System.out.println(getName() + "正在提交报告");
    }

    public void requestLeave() {
        System.out.println(getName() + "正在申请休假");
    }
}
java 复制代码
//Person类 父类
public class Person {

    //各类共有的成员变量
    private String name;     // 姓名
    private int age;         // 年龄
    private String gender;   // 性别
    private String idCard;   // 身份证号

    //创建构造方法
    public Person(String name, int age, String gender, String idCard) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.idCard = idCard;
    }

    // Getter方法 - 获取属性值
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getGender() {
        return gender;
    }

    public String getIdCard() {
        if (idCard != null && idCard.length() == 18) {
            return idCard.substring(0, 6) + "********" + idCard.substring(14);
        }
        return idCard;
    }

    // Setter方法 - 设置属性值
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        if (age >= 0 && age <= 150) {
            this.age = age;
        } else {
            System.out.println("年龄必须在0-150之间");
        }
    }

    //自我介绍
    public void introduce() {
        System.out.println("你好,我叫" + name + ",今年" + age + "岁");
    }

    // 工作(具体工作由子类决定)
    public void work() {
        System.out.println(name + "正在工作");
    }
}
java 复制代码
//Student类
public class Student extends Person {
    // 学生特有的属性
    private String studentId;  // 学号
    private String school;     // 学校
    private String major;      // 专业
    private double gpa;        // 平均成绩

    // 构造方法
    public Student(String name, int age, String gender, String idCard,
                   String studentId, String school, String major, double gpa) {
        // 调用父类的构造方法
        super(name, age, gender, idCard);

        // 设置学生特有的属性
        this.studentId = studentId;
        this.school = school;
        this.major = major;
        this.gpa = gpa;
    }

    // Getter方法

    public String getStudentId() {
        return studentId;
    }

    public String getSchool() {
        return school;
    }

    public String getMajor() {
        return major;
    }

    public double getGpa() {
        return gpa;
    }

    // Setter方法

    public void setStudentId(String studentId) {
        this.studentId = studentId;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    public void setGpa(double gpa) {
        if (gpa >= 0.0 && gpa <= 4.0) {
            this.gpa = gpa;
        } else {
            System.out.println("GPA必须在0.0-4.0之间");
        }
    }

    // 学生特有的方法
    public void attendClass() {
        System.out.println(getName() + "正在上课");
    }

    public void takeExam() {
        System.out.println(getName() + "正在考试");
    }
}
java 复制代码
public class Teacher extends Person {
    // 教师特有的属性
    private String teacherId;      // 工号
    private String school;         // 学校
    private String subject;        // 教授科目
    private double salary;         // 工资
    private int teachingYears;     // 教龄

    // 构造方法
    public Teacher(String name, int age, String gender, String idCard,
                   String teacherId, String school, String subject,
                   double salary, int teachingYears) {
        // 调用父类的构造方法
        super(name, age, gender, idCard);

        // 设置教师特有的属性
        this.teacherId = teacherId;
        this.school = school;
        this.subject = subject;
        this.salary = salary;
        this.teachingYears = teachingYears;
    }

    // Getter方法

    public String getTeacherId() {
        return teacherId;
    }

    public String getSchool() {
        return school;
    }

    public String getSubject() {
        return subject;
    }

    public double getSalary() {
        return salary;
    }

    public int getTeachingYears() {
        return teachingYears;
    }

    // Setter方法

    public void setTeacherId(String teacherId) {
        this.teacherId = teacherId;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public void setSalary(double salary) {
        if (salary >= 0) {
            this.salary = salary;
        } else {
            System.out.println("工资不能为负数");
        }
    }

    public void setTeachingYears(int teachingYears) {
        if (teachingYears >= 0) {
            this.teachingYears = teachingYears;
        } else {
            System.out.println("教龄不能为负数");
        }
    }
    // 教师特有的方法
    public void prepareLesson() {
        System.out.println(getName() + "正在备课");
    }

    public void gradePapers() {
        System.out.println(getName() + "正在批改作业");
    }

    public void haveMeeting() {
        System.out.println(getName() + "正在开会");
    }
}

现在我们来测试一下:

java 复制代码
//我们把各类的东西拿到这里看一下:
    private String studentId;  // 学号
    private String school;     // 学校
    private String major;      // 专业
    private double gpa;        // 平均成绩

//教师类
    private String teacherId;      // 工号
    private String school;         // 学校
    private String subject;        // 教授科目
    private double salary;         // 工资
    private int teachingYears;     // 教龄

//员工类
    private String employeeId;     // 员工编号
    private String company;        // 公司
    private String department;     // 部门
    private String position;       // 职位
    private double salary;         // 工资


public class PersonTest {
    public static void main(String[] args) {

        // 创建学生对象
        System.out.println("1. 创建学生对象");
        Student student = new Student("张三", 20, "男", "110101200001011234",
                "S2023001", "清华大学", "计算机科学", 3.8);

        // 创建教师对象
        System.out.println("2. 创建教师对象");
        Teacher teacher = new Teacher("李老师", 45, "女", "110101197801012345",
                "T2005001", "北京大学", "高等数学",
                15000.0, 20);

        // 创建员工对象
        System.out.println("3. 创建员工对象");
        Employee employee = new Employee("王五", 30, "男", "110101199301011236",
                "E2021001", "阿里巴巴", "技术部",
                "Java开发工程师", 25000.0);
        }
}

我们先创建所有类的对象,来试试看继承有没有成功:

学生对象:前面的姓名,年龄,性别,身份证全都是父类的成员变量,也就是共有的,而后面的成员变量则是学生类自己独有的,那么我们运行一下代码看看是否生成成功:

我们再试试创建对象的功能是否可访问:

java 复制代码
        
//接上上个代码后面
        System.out.println("\n=== 测试学生功能 ===");
        student.introduce();
        student.work();
        student.attendClass();
        student.takeExam();

        System.out.println("\n=== 测试教师功能 ===");
        teacher.introduce();
        teacher.work();
        teacher.prepareLesson();
        teacher.gradePapers();
        teacher.haveMeeting();

        System.out.println("\n=== 测试员工功能 ===");
        employee.introduce();
        employee.work();
        employee.attendMeeting();
        employee.submitReport();
        employee.requestLeave();

首先我们看看student.introduce()方法和work()方法,这是大家所共有的成员方法,而后面的三个是教师所独有的,我们运行一下,如果五个都访问成果则表示继承成功:

那么我们可以看到运行成功,那么学生和员工都是一样的

三、super关键字

super关键字代表父类对象。它有三种主要用途:

  1. 访问父类的属性

  2. 调用父类的方法

  3. 调用父类的构造方法

3.1 调用父类的方法

理解这个场景:

  • 要生一个孩子,必须先有父母
  • 创建子类对象时,必须先创建父类对象
  • Java强制要求:子类构造方法必须调用父类构造方法

文件结构如下:

先创建一个父类

java 复制代码
//父类
public class Parent {
    public Parent() {
        System.out.println("Parent构造方法被调用了!");
    }

    // 一个普通方法
    public void parentMethod() {
        System.out.println("这是父类的方法");
    }
}

再创建一个子类,这样就满足我们的第一个条件:

java 复制代码
public class Child extends Parent {
    // 构造方法
    public Child() {
        // 必须调用父类的构造方法
        super();  // 这行调用Parent的构造方法

        System.out.println("Child构造方法被调用了!");
    }

    // 子类自己的方法
    public void childMethod() {
        System.out.println("这是子类的方法");
    }
}

接下来我们进行测试一下,看看我们的代码结果super的时候会按照什么样的流程走下去:

java 复制代码
public class TestSimple {
    public static void main(String[] args) {
        Child child = new Child();
        child.parentMethod();
        child.childMethod();
    }
}

我们调试一下会发现:

new了child对象后,会进入Child中的super();

当我们执行super()后,会执行父类方法Parent:

执行完Parent()后,回到Child()并执行:

Child()执行完后重新回到主函数,再执行主函数的下一个方法:

进入parentMehton内

执行完毕后回到主函数,再进行下一个方法

最后函数结束


总流程如下

所以我们看到了以下的东西:

  1. 创建Child对象时,先执行了Parent的构造方法

  2. 然后才执行Child的构造方法

  3. 这是因为Child的构造方法中调用了super()

重要规则: 子类构造方法的第一行必须是super(),如果不写,Java会自动加上

3.2 带参数的构造方法调用

场景: 父亲有名字,儿子也有名字。创建儿子时,需要告诉父亲的名字。

java 复制代码
//父类
public class Father {
    String FatherName;

    public Father(String fatherName) {
        FatherName = fatherName;
        System.out.println("父亲的名字是" + fatherName);
    }
    // 显示父亲信息的方法
    public void showFatherInfo() {
        System.out.println("父亲信息:名字 = " + FatherName);
    }
}
java 复制代码
//子类
public class Son extends Father {
    String SonName;

    public Son(String FatherName,String sonName) {
        super(FatherName);
        this.SonName = sonName;
        System.out.println("儿子的名字是:" + sonName);
    }

    public void showSonInfo() {
        System.out.println("儿子信息:");
        System.out.println("  父亲名字 = " + FatherName);  // 继承自Father
        System.out.println("  儿子名字 = " + SonName);      // 自己的属性
    }
}
java 复制代码
public class TestParams {
    public static void main(String[] args) {
        Son son = new Son("张爸爸", "张小宝");
        System.out.println("\n=== 显示信息 ===");
        son.showFatherInfo();  // 调用继承的方法
        System.out.println();
        son.showSonInfo();     // 调用自己的方法

    }
}

其实主要的代码执行流程和上一个类似,这个只是多了个传参数的步骤,super把名字传给Father里

关键点:

  1. 创建Son时,需要传递两个参数:父亲名字和儿子名字

  2. super(fatherName)把父亲名字传给Father的构造方法

  3. 所以Father对象就有了名字

3.3 访问父类的属性(当父子有同名属性时)

java 复制代码
//父类
public class FamilyMember {
    // 父类的姓氏
    String lastName = "张";

    public void showLastName() {
        System.out.println("【父类方法】我的姓是:" + lastName);
    }
}
java 复制代码
//子类
public class ChildMember extends FamilyMember {
    // 子类自己的 lastName(与父类同名!)
    String lastName = "李";  // ← 关键:同名字段!

    public void showAllLastNames() {
        System.out.println("=== 查看不同方式访问 lastName ===");
        System.out.println("1. 直接访问 lastName:" + lastName);           // 子类的 "李"
        System.out.println("2. 使用 this.lastName:" + this.lastName);     // 子类的 "李"
        System.out.println("3. 使用 super.lastName:" + super.lastName);   // 父类的 "张"
    }

    // 调用父类的方法(该方法内部使用的是父类的 lastName)
    public void callParentMethod() {
        System.out.println("\n调用父类的 showLastName 方法:");
        super.showLastName(); // 输出:【父类方法】我的姓是:张
    }
}

这个例子主要是看看,在父子有同名属性时,我们可以通过this.方法名和super.方法名来指定调用父类还是子类的方法.

3.4 总结

用途 写法 说明
1. 调用父类的构造方法 super(...) 必须写在子类构造方法的第一行
2. 访问父类的属性 super.字段名 当子类和父类有同名字段时,用于访问父类的版本
3. 调用父类的方法 super.方法名(...) 当子类重写(override)了父类方法,但仍想调用父类原版逻辑时使用

规则 1:super() 必须是构造方法的第一条语句

规则 2:super 只能在实例上下文中使用

  • 不能在 static 方法(如 main)中使用 super
  • 不能在静态代码块中使用

规则 3:super.字段 仅在"字段遮蔽"时有意义

  • 如果子类没有定义 和父类同名的字段,那么:lastNamethis.lastNamesuper.lastName 完全等价
  • 只有当子类也声明了 lastName,三者才有区别

规则 4:super 不是引用变量,不能单独使用

第四章:继承中的构造方法

4.1 构造方法的调用顺序

我们有 3 个类:

  • A 是最顶层的"爷爷"类
  • B 继承自 A,是"爸爸"类
  • C 继承自 B,是"孙子"类

这叫 继承链C → B → A

在 Java 中,创建子类对象时,会自动先调用父类的构造方法,一层一层往上走,确保"祖先"先被初始化好。

super(...) 就是用来显式调用父类构造方法的关键字。

java 复制代码
//爷类
public class A {
    public A() {
        System.out.println("A的构造方法被调用");
    }

    public A(String message) {
        System.out.println("A的有参构造方法:" + message);
    }
}
java 复制代码
//B 父类
public class B extends A {
    public B() {
        // 编译器会自动添加 super();
        System.out.println("B的构造方法被调用");
    }

    public B(String message) {
        // 调用父类的有参构造方法
        super("来自B的调用");
        System.out.println("B的有参构造方法:" + message);
    }
}
java 复制代码
//C 子类
public class C extends B {
    public C() {
        // 编译器会自动添加 super();
        System.out.println("C的构造方法被调用");
    }

    public C(String message) {
        // 调用父类的有参构造方法
        super("来自C的调用");
        System.out.println("C的有参构造方法:" + message);
    }

    public C(String message1, String message2) {
        // 调用父类的有参构造方法
        super("来自C的双参数调用");
        System.out.println("C的双参数构造方法:" + message1 + ", " + message2);
    }
}
java 复制代码
//测试类
public class ConstructorTest {
    public static void main(String[] args) {
        System.out.println("=== 构造方法链测试 ===\n");

        System.out.println("1. 创建C的无参对象:");
        C c1 = new C();

        System.out.println("\n2. 创建C的有参对象:");
        C c2 = new C("Hello");

        System.out.println("\n3. 创建C的双参数对象:");
        C c3 = new C("Hello", "World");

        // 创建B的对象
        System.out.println("\n4. 创建B的对象:");
        B b = new B("测试B");

        // 创建A的对象
        System.out.println("\n5. 创建A的对象:");
        A a = new A("测试A");
    }
}

第 1 步:C c1 = new C();(创建 C 的无参对象)

  1. 进入 C() 构造方法

    • 代码中没写 super(),但 Java 自动加上 super();
    • 所以它会去调用 父类 B 的无参构造方法
  2. 进入 B() 构造方法

    • 同样,没写 super(),Java 自动加 super();
    • 所以它会去调用 父类 A 的无参构造方法
  3. 进入 A() 构造方法

    • 执行:System.out.println("A的构造方法被调用");
    • 输出:✅ A的构造方法被调用
  4. 回到 B() 构造方法

    • 执行:System.out.println("B的构造方法被调用");
    • 输出:✅ B的构造方法被调用
  5. 回到 C() 构构造方法

    • 执行:System.out.println("C的构造方法被调用");
    • 输出:✅ C的构造方法被调用

第 2 步:C c2 = new C("Hello");(带一个参数)

  1. 进入 C(String message)

    • 代码写了:super("来自C的调用");
    • 所以调用 B 的有参构造方法B("来自C的调用")
  2. 进入 B(String message)

    • 代码写了:super("来自B的调用");
    • 所以调用 A 的有参构造方法A("来自B的调用")
  3. 进入 A(String message)

    输出: A的有参构造方法:来自B的调用

  4. 回到 B(String message)

    输出: B的有参构造方法:来自C的调用

  5. 回到 C(String message)

    输出: C的有参构造方法:Hello

第 3 步:C c3 = new C("Hello", "World");(两个参数)

  1. 进入 C(String m1, String m2)

    • 执行:super("来自C的双参数调用");
    • → 调用 B("来自C的双参数调用")
  2. 进入 B(String message)

    • 执行:super("来自B的调用");
    • → 调用 A("来自B的调用")
  3. A 输出A的有参构造方法:来自B的调用

  4. B 输出B的有参构造方法:来自C的双参数调用

  5. C 输出C的双参数构造方法:Hello, World

第 4 步:B b = new B("测试B")

  1. 进入 B("测试B")
    • 执行 super("来自B的调用") → 调用 A("来自B的调用")
  2. A 输出: A的有参构造方法:来自B的调用
  3. B 输出: B的有参构造方法:测试B

第 5 步:A a = new A("测试A")

直接调用 A 的有参构造

4.2 打个比方(帮助记忆)

想象你在组装一个机器人:

  • A 是身体骨架
  • B 是装上手臂和腿
  • C 是戴上帽子、穿上衣服

你不能先戴帽子再装手臂!必须按顺序:骨架 → 四肢 → 装饰

super 就是你告诉工厂:"先帮我把上一级零件装好"。

4.3 总结:核心规律

规律 说明
1. 创建子类对象,必须先初始化父类 Java 自动帮你一层层调用父类构造方法
2. super() 必须写在构造方法第一行 否则编译报错
3. 如果不写 super(),Java 默认加 super(); 即调用父类的无参构造
4. 如果父类没有无参构造,子类必须显式写 super(...) 否则编译失败!
5. 构造方法调用顺序:从父类到子类(A → B → C) 先祖先后后代
相关推荐
嘻嘻嘻开心2 小时前
List集合接口
java·开发语言·list
源码获取_wx:Fegn08952 小时前
基于springboot + vue物业管理系统
java·开发语言·vue.js·spring boot·后端·spring·课程设计
cike_y2 小时前
JavaWeb-JDBC&事务回滚
java·开发语言·javaweb
青啊青斯2 小时前
python markdown转word【包括字体指定】
开发语言·python·word
corpse20102 小时前
trae下载依赖包特别慢!!!
开发语言·python
rainFFrain2 小时前
QT显示类控件---QSlider
开发语言·qt
dragoooon342 小时前
[C++——lesson30.数据结构进阶——「红黑树」]
开发语言·数据结构·c++
云泽8082 小时前
C++ STL 栈与队列完全指南:从容器使用到算法实现
开发语言·c++·算法
郑州光合科技余经理2 小时前
实战:攻克海外版同城生活服务平台开发五大挑战
java·开发语言·javascript·数据库·git·php·生活