20260722-笔记.md 30 KB

JavaSE 基础 — Day08 笔记

日期:2026-07-22
项目c260722
作者:WanJL


一、继承(Inheritance)

1. 继承的概念

文件Demo01.java

继承是 Java 三大特征之一(封装、继承、多态)。继承可以让子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法。

继承的关键字是 extends,直译是「扩展」,含义是子类在父类的基础上进行扩展。

核心思想

  • 子类具有父类的特征
  • 父类是根据多个具有相同特征的子类所抽取出来的公共部分

类的层次结构示例

动物 类
  |- 哺乳动物 类
     |- 猫科动物 类
        |- 猫 类
        |- 狮子 类
        |- 老虎 类
     |- 犬科动物 类
        |- 狼 类
        |- 狗 类
  |- 爬行动物 类
  |- 两栖动物 类

2. 继承的格式

文件Demo01.java

class 子类 extends 父类 {
    // 子类自己的成员
}

示例

class Animal {                  // 父类
}

class Bird extends Animal {     // 子类 Bird 继承 Animal
}

class Penguin extends Bird {    // 子类 Penguin 继承 Bird(多层继承)
}

3. 继承体系示例

文件Animal.javaBird.javaPenguin.java

// 父类 Animal —— 定义所有动物共有的行为
public class Animal {
    public void eat() {
        System.out.println("吃......");
    }
    public void sleep() {
        System.out.println("睡......");
    }
}

// 子类 Bird —— 继承 Animal,追加 fly 方法
public class Bird extends Animal {
    public void fly() {
        System.out.println("飞.......");
    }
}

// 子类 Penguin —— 继承 Bird(多层继承)
public class Penguin extends Bird {
    // 继承了 Animal 的 eat()、sleep() 和 Bird 的 fly()
}

4. 继承的使用

文件Test01.java

public class Test01 {
    public static void main(String[] args) {
        // 父类对象只能使用自己的方法
        Animal animal = new Animal();
        animal.eat();
        animal.sleep();

        // Bird 对象可以使用父类 Animal 的方法 + 自己的方法
        Bird bird = new Bird();
        bird.eat();     // 继承自 Animal
        bird.sleep();   // 继承自 Animal
        bird.fly();     // 自己的方法

        // Penguin 对象可以使用所有继承来的方法
        Penguin p = new Penguin();
        p.eat();        // 继承自 Animal → Bird → Penguin
        p.sleep();      // 继承自 Animal → Bird → Penguin
    }
}

5. 继承的好处

文件Demo01.java

好处 说明
代码复用性 多个类的相同成员可以放在同一个父类中,子类自动拥有
代码可维护性 父类方法修改一处,所有子类都继承修改后的版本
建立类与类的关系 产生父子类关系后,子类可使用父类中非私有化成员
// 如果修改 Animal 的 eat() 方法,所有子类都会生效
public class Animal {
    public void eat() {
        System.out.println("正在吃东西......");  // 改这里就行
    }
}

6. 继承的弊端——耦合性

文件Demo01.java

继承让类和类之间产生了关系,导致耦合性增强

  • 父类发生变化时,子类也不得不跟着变化
  • 子类依赖父类的存在,如果父类不存在,子类就报错
  • 这削弱了子类的独立性

耦合关系(Coupling):类与类之间的依赖程度。程序设计很多时候都在研究如何解耦

7. 继承的使用场景——is...a 关系

文件Demo01.java

使用继承前要考虑类和类之间是否存在 is...a 关系(谁是谁的一种):

正确(符合 is...a) 错误(不符合 is...a)
老师人的一种 汽车学生的一种 ✗
学生人的一种
动物的一种
动物生物的一种
// 正确的继承设计
class Person { }
class Student extends Person { }   // 学生是人的一种 ✓

// 错误的继承设计
class Car { }
class Student extends Car { }      // 学生不是汽车的一种 ✗

8. 方法重写(Method Override)

文件Demo01.javaBird.javaPenguin.java

当子类中出现与父类 完全相同的方法名、参数列表和返回值类型 的方法时,称为 方法重写(Override)。子类会覆盖父类的方法,默认调用子类的版本。

// 父类 Animal
public class Animal {
    public void eat() {
        System.out.println("吃......");
    }
}

// 子类 Bird —— 重写父类的 eat() 方法
public class Bird extends Animal {
    // @Override 是重写注解(可选),加上后编译器会检查该方法是否真的重写了父类方法
    // 即使不加 @Override,只要方法签名完全一致,也是重写
    public void eat() {
        System.out.println("鸟吃自己的.....");
    }
}

// 子类 Penguin —— 重写父类 Bird 的 fly() 方法
public class Penguin extends Bird {
    @Override   // 推荐加上,便于阅读和检查
    public void fly() {
        System.out.println("我不飞..我肚皮贴着冰面滑......");
    }
}

重写 vs 非重写

情况 结果
子类方法与父类方法 签名完全一致 重写(Override)
子类方法与父类方法 方法名不同 子类特有的方法,不是重写

测试效果

// Test01.java
public class Test01 {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.eat();            // 吃......

        Bird bird = new Bird();
        bird.eat();              // 鸟吃自己的.....(重写后调用子类版本)

        Penguin p = new Penguin();
        p.fly();                 // 我不飞..我肚皮贴着冰面滑......(重写后调用子类版本)
    }
}

注意:重写发生在 子类和父类之间,方法签名必须完全一致(方法名 + 参数列表 + 返回值类型)。重写不是必须加 @Override 注解,但建议加上,因为它能让编译器帮助检查是否正确重写。


9. super 关键字

文件Granddad.javaDad.javaSon.javaTest02.java

super 关键字用于在子类中 引用父类的成员(方法或属性),主要用在以下场景:

使用方式 说明
super.父类方法() 调用父类中被重写的方法
super.父类属性 访问父类中与子类同名的属性

示例:多层链式调用 super.eat()

// Granddad.java —— 爷爷类(顶层父类)
public class Granddad {
    public void eat() {
        System.out.println("爷爷爱喝酒....");
    }
}

// Dad.java —— 父亲类(继承 Granddad)
public class Dad extends Granddad {
    public void eat() {
        super.eat();               // 先调用爷爷的 eat()
        System.out.println("爸爸爱吃肉....");
    }
}

// Son.java —— 儿子类(继承 Dad)
public class Son extends Dad {
    public void eat() {
        super.eat();               // 先调用爸爸的 eat()(爸爸内部又会调用爷爷的 eat())
        System.out.println("儿子不吃饭....");
    }
}

测试效果

// Test02.java
public class Test02 {
    public static void main(String[] args) {
        Son s = new Son();
        s.eat();
    }
}

预期输出

爷爷爱喝酒....
爸爸爱吃肉....
儿子不吃饭....

调用链分析Son.eat()super.eat() 调用 Dad.eat()Dad.eat() 中的 super.eat() 调用 Granddad.eat() → 输出"爷爷爱喝酒...." → 回到 Dad 输出"爸爸爱吃肉...." → 回到 Son 输出"儿子不吃饭...."。形成了方法的 链式调用


10. 同名属性的处理

文件Bird.javaPenguin.javaTest01.java

当子类和父类定义了 同名的成员变量 时,两个变量会 同时存在 于子类对象中。访问规则如下:

访问方式 访问的是
变量名this.变量名 子类自己 的属性
super.变量名 父类 的属性

示例

// Bird.java —— 父类中定义了 s2(默认权限)、s3(protected 权限)
public class Bird extends Animal {
    String s2;                // 默认权限
    protected String s3;      // protected 权限
}

// Penguin.java —— 子类中定义了同名的 s2、s3
public class Penguin extends Bird {
    String s3;                // 与父类 Bird 的 s3 同名

    @Override
    public void fly() {
        System.out.println("调用父类的s2属性:" + super.s2);   // 访问 Bird 的 s2
        System.out.println("调用自己的s2属性:" + this.s2);    // 访问 Penguin 的 s2(如果没有则继承 Bird 的)
        System.out.println("调用父类的s3属性:" + super.s3);   // 访问 Bird 的 s3
        System.out.println("调用自己的s3属性:" + this.s3);    // 访问 Penguin 的 s3
    }
}

测试效果

// Test01.java
Penguin p = new Penguin();
p.s3 = "哈哈哈哈";      // 设置 Penguin 自己的 s3
p.s2 = "s2222222";      // 设置 Bird 的 s2(Penguin 没有同名 s2,所以直接继承使用)
p.fly();

总结:如果子类没有定义同名的属性,this.属性super.属性 访问的是同一个父类属性。如果子类定义了同名属性,则 this 访问自己的,super 访问父类的。


11. Java 继承的限制

文件Demo01.java

Java 的继承机制有以下重要限制:

① 单继承(Single Inheritance)

Java 中一个子类 只能有一个直接父类,不支持 C++ 中的多继承。

// ❌ 错误:Java 不支持多继承
class C extends A, B {  // 编译报错!
}

// ✅ 正确:一个子类只能有一个直接父类
class B extends A {  // 正确
}

② 多层继承(Multi-level Inheritance)

Java 支持多层继承,即一个类的父类可以继承自其他类。

// ✅ 多层继承:Son → Dad → Granddad
class Granddad { }
class Dad extends Granddad { }     // Dad 的直接父类是 Granddad
class Son extends Dad { }          // Son 的直接父类是 Dad
                                   // Son 的间接父类是 Granddad
概念 说明
直接父类 子类通过 extends 直接继承的类(如 Son 的 Dad)
间接父类 子类的父类的父类……(如 Son 的 Granddad)

③ Object——所有类的根父类

文件Demo01.java

Java 中 所有的类都默认继承自 Object。如果一个类没有显式使用 extends 关键字,它也会隐式继承 Object

// 以下两种写法等价:
public class Animal { }                // 隐式继承 Object
public class Animal extends Object { } // 显式继承 Object

Object 类中定义了一些所有对象都具备的基本方法(如 toString()equals()hashCode() 等)。


12. 访问修饰符在继承中的体现

文件Bird.java

子类能访问的父类成员范围取决于父类成员的访问修饰符:

修饰符 本类 同包子类 异包子类 所有类
private
默认(缺省)
protected
public
public class Bird extends Animal {
    private String s1;      // 私有的 —— 仅本类可访问
    String s2;              // 默认的 —— 同包可访问
    protected String s3;    // protected —— 同包 + 子类可访问
    public String s4;       // 公共的 —— 所有类可访问
}

13. 继承中变量的访问特点——就近原则

文件Demo02.javaSon.java

在子类中访问一个变量时,采用 就近原则 查找:

查找顺序 查找范围 示例(Son 中访问 a
1️⃣ 子类的 局部范围(方法内部) int a = 10;(局部变量)
2️⃣ 子类的 成员范围(成员变量) int a;(子类成员变量)
3️⃣ 父类 的成员范围 int c;(Dad 的成员变量)
4️⃣ 父类的父类……直到 Object int d;(Granddad 的成员变量)
如果都没找到 编译报错
// Son.java —— 演示就近原则
public class Son extends Dad {
    int a;          // 子类的成员变量(第2层)
    int b;          // 子类的成员变量(第2层)

    public void eat() {
        int a = 10;   // 局部变量(第1层)
        super.eat();

        System.out.println(a);  // 10  —— 局部范围找到 a
        System.out.println(b);  // 0   —— 局部无 b → 子类成员找到 b
        System.out.println(c);  // 0   —— 子类无 c → 父类 Dad 找到 c
        System.out.println(d);  // 0   —— 父类无 d → 祖父 Granddad 找到 d
    }
}

// Granddad.java —— 顶层父类定义了 d
public class Granddad {
    int d;
    public void eat() {
        System.out.println("爷爷爱喝酒....");
    }
}

// Dad.java —— 父类定义了 c
public class Dad extends Granddad {
    int c;
    public void eat() {
        super.eat();
        System.out.println("爸爸爱吃肉....");
    }
}

总结:变量的查找路径为 局部 → 本类成员 → 父类成员 → 祖父类成员 → … → Object。如果一直找到 Object 都没有,则编译报错。


14. this vs super 完整对比

文件Demo02.java

thissuper 是 Java 中两个非常重要的关键字:

关键字 含义 示例
this 代表 本类 对象的引用 this.namethis.eat()this()
super 代表 父类 对象的引用 super.namesuper.eat()super()

在三种场景中的使用对比

场景 this 用法 super 用法
成员变量 this.成员变量 —— 访问本类的成员变量 super.成员变量 —— 访问父类的成员变量
成员方法 this.成员方法() —— 调用本类的成员方法 super.成员方法() —— 调用父类的成员方法
构造方法 this() / this(参数) —— 调用本类的其他构造方法 super() / super(参数) —— 调用父类的构造方法
// Demo02.java(注释中总结)
/*
this 代表本类对象的引用
super 代表父类对象的引用

成员变量中:
    this.成员变量  --> 访问本类的成员变量
    super.成员变量 --> 访问父类的成员变量
成员方法中:
    this.成员方法  --> 调用本类的成员方法
    super.成员方法 --> 调用父类的成员方法
构造方法中:
    this()      --> 访问本类的无参构造方法
    this(参数)   --> 访问本类的有参构造方法
    super()      --> 访问父类的无参构造方法
    super(参数)   --> 访问父类的有参构造方法
*/

注意this()super() 都必须写在构造方法的 第一行,且 不能同时出现

// Zi.java —— 演示 super() 和 this() 不能共存
public class Zi extends Fu {
    public Zi(String a) {
        super();    // ✅ 正确:放在第一行
        // this();  // ❌ 错误:如果取消注释,会和 super() 冲突
    }
}

15. 继承中构造方法的特点

文件Demo02.javaAnimal.javaDog.javaTest03.javaFu.javaZi.javaPerson.javaStudent.java

15.1 子类构造方法默认调用父类无参构造

文件Animal.javaDog.javaTest03.java

子类的所有构造方法(有参或无参)都会 默认调用父类的无参构造方法。每个子类构造方法的 第一句 默认都是 super()

// Animal.java —— 父类:添加无参构造方法打印信息
public class Animal {
    public Animal() {
        System.out.println("动物类的无参构造方法");
    }
}

// Dog.java —— 子类:没有写任何构造方法,默认有无参构造
public class Dog extends Animal {
    // 隐藏的默认构造方法:
    // public Dog() {
    //     super();  // 自动调用父类的无参构造
    // }
}

// Test03.java —— 测试
public class Test03 {
    public static void main(String[] args) {
        Dog d = new Dog();
    }
}

输出结果

动物类的无参构造方法

原理:子类在初始化(创建对象)之前,一定要先完成对父类对象的创建。因为子类会继承父类的数据,可能还会使用父类的数据,所以必须先创建父类对象。这就是为什么每个子类构造方法的第一句默认都是 super()

15.2 父类没有无参构造时的处理

文件Fu.javaZi.javaPerson.javaStudent.java

情况一:父类 没有 无参构造方法(只有有参构造),子类必须手动调用父类的有参构造。

// Fu.java —— 父类:只有有参构造
public class Fu {
    private String name;

    public Fu(String name) {   // 有参构造覆盖了默认无参构造
        this.name = name;
    }
}

// Zi.java —— 子类:必须手动调用父类的有参构造
public class Zi extends Fu {
    public Zi() {
        super("默认名");  // ❗ 必须手动调用父类的有参构造,否则编译报错
        System.out.println("子类构造方法");
    }
}

情况二:父类 有无参构造但被 private 修饰,子类也无法调用。

// Fu.java —— 父类有无参构造但是 private
// private Fu() { }   // private 构造方法,子类不可见

15.3 综合示例:Person → Student

文件Person.javaStudent.java

// Person.java —— 父类只有有参构造
public class Person {
    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

// Student.java —— 子类必须手动调用 super(name, age)
public class Student extends Person {
    private String school;

    public Student(String name, Integer age, String school) {
        super(name, age);    // 调用父类的有参构造,传入参数
        this.school = school;
    }
}

核心规则

  1. 子类构造方法 默认第一句super()(调用父类无参构造)
  2. 如果父类 没有无参构造,子类必须通过 super(参数) 指定调用父类的有参构造
  3. 如果父类 有无参构造但是 private,子类同样无法调用,也需要指定其他构造
  4. super(参数) 必须在子类构造方法的 第一行

包名exercise.studentSystem

课堂练习题

题目要求

使用构造方法完成完整的学生成绩管理系统,包含三个类:

Student 类(实体类)

文件Student.java

public class Student {
    private int id;           // 学号
    private String name;      // 姓名
    private double javaScore; // Java 成绩
    private double mysqlScore;// MySQL 成绩

    // 全参构造方法
    public Student(int id, String name, double javaScore, double mysqlScore) {
        this.id = id;
        this.name = name;
        this.javaScore = javaScore;
        this.mysqlScore = mysqlScore;
    }

    // getter/setter...

    // 计算平均分的方法
    public double getAverage() {
        return (this.javaScore + this.mysqlScore) / 2;
    }
}

StudentSystem 类(业务类)

文件StudentSystem.java

public class StudentSystem {
    private Student[] students;  // 学生数组
    private int count;           // 当前学生数量

    // 构造方法:初始化指定容量的学生数组
    public StudentSystem(int capacity) {
        students = new Student[capacity];
        count = 0;
    }

    // 添加学生到数组中
    public void addStudent(Student s) {
        if (count >= this.students.length) {
            System.out.println("数组已满,添加失败");
        } else {
            students[count] = s;
            count++;
        }
    }

    // 输出所有学生信息(含平均分)
    public void printAll() {
        for (Student s : students) {
            System.out.println("学号:" + s.getId() + ",姓名:" + s.getName()
                + ",Java成绩:" + s.getJavaScore() + ",MySQL成绩:" + s.getMysqlScore()
                + ",平均成绩:" + s.getAverage());
        }
    }

    // 按平均分降序排序(冒泡排序)
    public void sortByAverage() {
        for (int i = 0; i < students.length - 1; i++) {
            for (int j = 0; j < students.length - 1 - i; j++) {
                if (students[j].getAverage() < students[j + 1].getAverage()) {
                    Student temp = students[j];
                    students[j] = students[j + 1];
                    students[j + 1] = temp;
                }
            }
        }
    }

    // 返回平均分最高的学生对象
    public Student getTopStudent() {
        Student s = students[0];
        for (int i = 1; i < students.length; i++) {
            if (s.getAverage() < students[i].getAverage()) {
                s = students[i];
            }
        }
        return s;
    }
}

涉及知识点

知识点 说明
全参构造方法 创建对象时直接初始化所有属性
对象数组 存储多个学生对象
增强 for 循环 遍历数组输出信息
冒泡排序 按对象属性(平均分)排序
方法调用链 students[j].getAverage() 获取对象属性进行比较
数组满判断 count >= students.length 防止越界

三、课后作业

作业 1:猜数游戏(面向对象版)⭐️⭐️⭐️⭐️

包名homework.p08_guessgame

文件GuessGame.javaGuessGameTest.java

使用构造方法 + Random + 方法,将猜数字游戏改造为面向对象版本。

GuessGame 类

public class GuessGame {
    private int target;     // 目标数字(随机生成)
    private int maxRange;   // 最大范围
    private int attempts;   // 已猜次数

    // 构造方法:生成随机目标数字
    public GuessGame(int maxRange) {
        Random random = new Random();
        this.maxRange = maxRange;
        this.attempts = 0;
        target = random.nextInt(this.maxRange) + 1;  // 1~maxRange
    }

    // 猜数字方法
    public String guess(int num) {
        this.attempts++;
        if (num > target) {
            return "猜大了";
        } else if (num < this.target) {
            return "猜小了";
        } else {
            return "猜对了";
        }
    }

    public int getAttempts() {
        return this.attempts;
    }
}

GuessGameTest 测试类

public class GuessGameTest {
    public static void main(String[] args) {
        GuessGame gg = new GuessGame(100);
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.print("请输入你猜的数字:");
            int num = sc.nextInt();
            String guess = gg.guess(num);
            System.out.println(guess);
            if (guess == "猜对了") {  // 注意:字符串比较建议用 equals()
                break;
            }
        }
        System.out.println("恭喜你!一共猜了 " + gg.getAttempts() + " 次");
    }
}

作业 2:BookManager 图书管理系统 ⭐️⭐️⭐️⭐️

包名homework.p09_bookmanager

文件Book.javaBookManager.javaBookManagerTest.java

综合练习:构造方法 + 封装 + 对象数组 + 排序 + 查找

Book 类(实体类):

public class Book {
    private int id;        // 编号
    private String title;  // 书名
    private double price;  // 价格

    // 全参构造方法
    public Book(int id, String title, double price) {
        this.id = id;
        this.title = title;
        this.price = price;
    }
    // getter/setter...
}

BookManager 类(业务类):

public class BookManager {
    // 初始化 5 本图书
    public Book[] initBooks() {
        Book b1 = new Book(1001, "Java从入门到精通", 79.0);
        Book b2 = new Book(1002, "数据结构与算法", 65.0);
        Book b3 = new Book(1003, "设计模式之禅", 58.0);
        Book b4 = new Book(1004, "深入理解JVM", 89.0);
        Book b5 = new Book(1005, "计算机网络", 45.0);
        Book[] books = {b1, b2, b3, b4, b5};  // 静态初始化
        return books;
    }

    // 遍历所有图书
    public void printBooks(Book[] books) {
        for (Book b : books) {
            System.out.println("编号:" + b.getId() + ",书名:" + b.getTitle()
                + ",价格:" + b.getPrice());
        }
    }

    // 按价格从高到低排序(冒泡排序)
    public void sortByPrice(Book[] books) {
        for (int i = 0; i < books.length - 1; i++) {
            for (int j = 0; j < books.length - 1 - i; j++) {
                if (books[j].getPrice() < books[j + 1].getPrice()) {
                    Book temp = books[j];
                    books[j] = books[j + 1];
                    books[j + 1] = temp;
                }
            }
        }
    }

    // 根据书名查找图书
    public Book searchByTitle(Book[] books, String title) {
        for (Book b : books) {
            if (b.getTitle() == title) {  // 建议用 equals()
                return b;
            }
        }
        return null;
    }
}

BookManagerTest 测试类

public class BookManagerTest {
    public static void main(String[] args) {
        BookManager bm = new BookManager();
        Book[] books = bm.initBooks();

        System.out.println("========== 原始顺序 ==========");
        bm.printBooks(books);

        bm.sortByPrice(books);
        System.out.println("========== 按价格从高到低排序 ==========");
        bm.printBooks(books);

        System.out.println("========== 查找图书 ==========");
        String bookName = "设计模式之禅";
        Book book = bm.searchByTitle(books, bookName);
        if (book == null) {
            System.out.println("未找到该图书!");
        } else {
            System.out.println("找到了!编号:" + book.getId() + ",价格:" + book.getPrice());
        }
    }
}

四、今日知识点总结

核心知识点

知识点 重要程度 说明
继承的概念 ⭐⭐⭐⭐⭐ Java 三大特征之一,子类 extends 父类
继承的格式 ⭐⭐⭐⭐⭐ class 子类 extends 父类 {}
继承的好处与弊端 ⭐⭐⭐⭐ 提高复用性但增强耦合性
is...a 关系判断 ⭐⭐⭐⭐ 使用继承前必须判断是否符合 is...a
方法重写(Override) ⭐⭐⭐⭐⭐ 子类覆盖父类方法,方法签名必须完全一致
@Override 注解 ⭐⭐⭐⭐ 可选的检查注解,推荐加上帮助编译器校验
super 关键字 ⭐⭐⭐⭐⭐ super.方法() 调用父类方法,super.属性 访问父类属性
同名属性处理 ⭐⭐⭐⭐ 父子类同名属性同时存在,this 访问自己的,super 访问父类的
变量的就近原则 ⭐⭐⭐⭐⭐ 变量查找路径:局部 → 本类成员 → 父类成员 → 祖父类成员 → Object
this vs super 对比 ⭐⭐⭐⭐ this=本类引用,super=父类引用,在变量/方法/构造方法三场景对比
构造方法继承特点 ⭐⭐⭐⭐⭐ 子类构造方法默认第一句 super() 调用父类无参构造
父类无无参构造处理 ⭐⭐⭐⭐⭐ 父类无无参构造时,子类必须手动 super(参数) 指定有参构造
单继承 ⭐⭐⭐⭐⭐ Java 一个子类只能有一个直接父类
多层继承 ⭐⭐⭐⭐ 支持链式继承(Son → Dad → Granddad)
Object 根类 ⭐⭐⭐⭐ Java 所有类都隐式继承 Object
访问修饰符在继承中 ⭐⭐⭐⭐ private 不可继承,protected 子类可访问
构造方法 + 对象数组 + 冒泡排序综合应用 ⭐⭐⭐⭐⭐ 学生管理系统、图书管理系统

注意事项

  1. 单继承:Java 中一个类只能有一个直接父类(区别于 C++ 的多继承)
  2. 多层继承 ≠ 多继承:Java 支持 Son → Dad → Granddad 这样的链式继承,但不支持同时继承多个类
  3. 私有成员不可访问:子类不能直接使用父类 private 修饰的成员
  4. 构造方法不可继承:父类的构造方法不会被子类继承,子类通过 super(参数) 调用父类构造方法
  5. 子类构造方法默认调用 super():每个子类构造方法的第一句默认都是 super(),如果父类没有无参构造,必须手动 super(参数)
  6. 方法重写 vs 方法重载
    • 重写(Override):父子类之间,方法签名完全一致
    • 重载(Overload):同一个类中,方法名相同参数列表不同
  7. @Override 注解:不强制但建议加上,可以帮助编译器检查是否真正重写了父类方法
  8. 变量访问就近原则:局部 → 本类成员 → 父类成员 → 祖父类成员 → …… → Object
  9. super()this() 不能同时出现:都必须写在构造方法的第一行
  10. 继承的耦合性:合理设计继承层次,避免过深的继承链,优先考虑组合而非继承

拓展阅读

  • final 关键字对继承的限制(final 类不能被继承,final 方法不能被重写)
  • 继承与组合(Composition)的对比——优先使用组合而非继承
  • Object 类的常见方法:toString()equals()hashCode()getClass()
  • 方法重写的规则(访问权限不能更低、返回值类型可以协变、抛出异常不能更宽等)