Skip to content

🔗 继承

继承概述

继承(Inheritance)是面向对象编程的三大特性之一,它允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码复用。

继承的特点

  • 代码复用:子类可以复用父类的代码
  • 扩展性:子类可以添加新的属性和方法
  • 多态基础:继承是实现多态的基础
  • 单继承:Java 只支持单继承(一个类只能继承一个父类)

继承的语法

基本语法

java
// 父类(基类、超类)
class Parent {
    // 父类的成员
}

// 子类(派生类)
class Child extends Parent {
    // 子类的成员
}

继承示例

java
// 父类
public class Animal {
    protected String name;
    protected int age;
    
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void eat() {
        System.out.println(name + " 正在吃东西");
    }
    
    public void sleep() {
        System.out.println(name + " 正在睡觉");
    }
    
    public void displayInfo() {
        System.out.println("名称: " + name + ", 年龄: " + age);
    }
}

// 子类
public class Dog extends Animal {
    private String breed;  // 子类特有的属性
    
    public Dog(String name, int age, String breed) {
        super(name, age);  // 调用父类构造方法
        this.breed = breed;
    }
    
    // 子类特有的方法
    public void bark() {
        System.out.println(name + " 正在叫: 汪汪汪");
    }
    
    // 重写父类方法
    @Override
    public void displayInfo() {
        super.displayInfo();  // 调用父类方法
        System.out.println("品种: " + breed);
    }
}

// 使用
Dog dog = new Dog("旺财", 3, "金毛");
dog.eat();         // 继承自父类
dog.sleep();       // 继承自父类
dog.bark();        // 子类特有方法
dog.displayInfo(); // 重写的方法

super 关键字

super 的用途

  1. 调用父类构造方法super(参数)
  2. 调用父类方法super.方法名()
  3. 访问父类成员变量super.变量名

super 示例

java
public class Parent {
    protected String name;
    
    public Parent(String name) {
        this.name = name;
    }
    
    public void display() {
        System.out.println("父类方法: " + name);
    }
}

public class Child extends Parent {
    private String childName;
    
    public Child(String name, String childName) {
        super(name);  // 调用父类构造方法
        this.childName = childName;
    }
    
    @Override
    public void display() {
        super.display();  // 调用父类方法
        System.out.println("子类方法: " + childName);
    }
    
    public void showParentName() {
        System.out.println(super.name);  // 访问父类成员变量
    }
}

方法重写(Override)

重写规则

  1. 方法名、参数列表必须相同
  2. 返回类型必须相同或是父类返回类型的子类型
  3. 访问权限不能比父类更严格
  4. 不能抛出比父类更多的异常(或父类异常的子类)

重写示例

java
public class Shape {
    public double calculateArea() {
        return 0;
    }
    
    public void display() {
        System.out.println("这是一个形状");
    }
}

public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    // 重写父类方法
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public void display() {
        System.out.println("这是一个圆形,半径: " + radius);
    }
}

public class Rectangle extends Shape {
    private double width;
    private double height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double calculateArea() {
        return width * height;
    }
    
    @Override
    public void display() {
        System.out.println("这是一个矩形,宽: " + width + ", 高: " + height);
    }
}

@Override 注解

java
public class Child extends Parent {
    @Override  // 明确表示这是重写方法
    public void method() {
        // 方法体
    }
}

final 关键字

final 修饰类

java
// final 类不能被继承
public final class FinalClass {
    // ...
}

// ❌ 错误:不能继承 final 类
// public class Child extends FinalClass { }

final 修饰方法

java
public class Parent {
    // final 方法不能被重写
    public final void finalMethod() {
        System.out.println("这是最终方法");
    }
}

public class Child extends Parent {
    // ❌ 错误:不能重写 final 方法
    // @Override
    // public void finalMethod() { }
}

final 修饰变量

java
public class Example {
    // final 变量必须初始化,且不能修改
    private final int CONSTANT = 100;
    
    // final 实例变量
    private final String name;
    
    public Example(String name) {
        this.name = name;  // 必须在构造方法中初始化
    }
}

访问修饰符与继承

访问修饰符的继承规则

修饰符类内包内子类包外
private
default
protected
public
java
public class Parent {
    private int privateVar;        // 子类不能访问
    int defaultVar;                // 同包子类可以访问
    protected int protectedVar;    // 子类可以访问
    public int publicVar;          // 子类可以访问
}

public class Child extends Parent {
    public void method() {
        // System.out.println(privateVar);   // ❌ 错误
        // System.out.println(defaultVar);   // ❌ 错误(如果不同包)
        System.out.println(protectedVar);   // ✅ 可以
        System.out.println(publicVar);      // ✅ 可以
    }
}

构造方法与继承

构造方法调用顺序

java
public class Grandparent {
    public Grandparent() {
        System.out.println("Grandparent 构造方法");
    }
}

public class Parent extends Grandparent {
    public Parent() {
        System.out.println("Parent 构造方法");
    }
}

public class Child extends Parent {
    public Child() {
        System.out.println("Child 构造方法");
    }
}

// 创建对象
Child child = new Child();
// 输出:
// Grandparent 构造方法
// Parent 构造方法
// Child 构造方法

显式调用父类构造方法

java
public class Parent {
    private String name;
    
    public Parent(String name) {
        this.name = name;
        System.out.println("Parent 构造方法: " + name);
    }
}

public class Child extends Parent {
    private int age;
    
    public Child(String name, int age) {
        super(name);  // 必须显式调用父类构造方法
        this.age = age;
        System.out.println("Child 构造方法: " + age);
    }
}

继承的层次结构

多级继承

java
// 动物类
public class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void eat() {
        System.out.println(name + " 正在吃东西");
    }
}

// 哺乳动物类
public class Mammal extends Animal {
    public Mammal(String name) {
        super(name);
    }
    
    public void breathe() {
        System.out.println(name + " 正在呼吸");
    }
}

// 狗类
public class Dog extends Mammal {
    public Dog(String name) {
        super(name);
    }
    
    public void bark() {
        System.out.println(name + " 正在叫");
    }
}

// 使用
Dog dog = new Dog("旺财");
dog.eat();     // 继承自 Animal
dog.breathe(); // 继承自 Mammal
dog.bark();    // Dog 自己的方法

Object 类

Object 类的方法

所有类都继承自 Object 类,可以重写以下方法:

java
public class MyClass {
    // 重写 toString 方法
    @Override
    public String toString() {
        return "MyClass{...}";
    }
    
    // 重写 equals 方法
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        // 比较逻辑
        return true;
    }
    
    // 重写 hashCode 方法
    @Override
    public int hashCode() {
        // 计算哈希码
        return Objects.hash(...);
    }
}

常用 Object 方法

java
Object obj = new Object();

// toString:返回对象的字符串表示
String str = obj.toString();

// equals:比较对象是否相等
boolean equal = obj.equals(anotherObj);

// hashCode:返回对象的哈希码
int hash = obj.hashCode();

// getClass:获取对象的类
Class<?> clazz = obj.getClass();

继承的优缺点

优点

  1. 代码复用:子类可以复用父类的代码
  2. 扩展性:子类可以添加新功能
  3. 多态支持:为实现多态提供基础
  4. 维护性:修改父类影响所有子类

缺点

  1. 耦合度高:子类与父类紧密耦合
  2. 单继承限制:Java 只支持单继承
  3. 设计复杂:继承层次过深会难以理解

完整示例

java
// 父类:员工
public class Employee {
    protected String name;
    protected int id;
    protected double salary;
    
    public Employee(String name, int id, double salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }
    
    public void work() {
        System.out.println(name + " 正在工作");
    }
    
    public void displayInfo() {
        System.out.println("员工姓名: " + name);
        System.out.println("员工ID: " + id);
        System.out.println("工资: " + salary);
    }
    
    public double calculateSalary() {
        return salary;
    }
}

// 子类:经理
public class Manager extends Employee {
    private double bonus;
    
    public Manager(String name, int id, double salary, double bonus) {
        super(name, id, salary);
        this.bonus = bonus;
    }
    
    @Override
    public void work() {
        System.out.println(name + " 正在管理工作");
    }
    
    @Override
    public double calculateSalary() {
        return salary + bonus;  // 工资 + 奖金
    }
    
    @Override
    public void displayInfo() {
        super.displayInfo();
        System.out.println("奖金: " + bonus);
        System.out.println("总工资: " + calculateSalary());
    }
    
    // 经理特有的方法
    public void manageTeam() {
        System.out.println(name + " 正在管理团队");
    }
}

// 子类:程序员
public class Programmer extends Employee {
    private String programmingLanguage;
    
    public Programmer(String name, int id, double salary, String language) {
        super(name, id, salary);
        this.programmingLanguage = language;
    }
    
    @Override
    public void work() {
        System.out.println(name + " 正在用 " + programmingLanguage + " 编程");
    }
    
    @Override
    public void displayInfo() {
        super.displayInfo();
        System.out.println("编程语言: " + programmingLanguage);
    }
    
    // 程序员特有的方法
    public void code() {
        System.out.println(name + " 正在编写代码");
    }
}

// 使用示例
public class InheritanceExample {
    public static void main(String[] args) {
        Employee emp = new Employee("张三", 1, 5000);
        Manager mgr = new Manager("李四", 2, 10000, 5000);
        Programmer prog = new Programmer("王五", 3, 8000, "Java");
        
        emp.work();
        emp.displayInfo();
        
        System.out.println("---");
        
        mgr.work();
        mgr.displayInfo();
        mgr.manageTeam();
        
        System.out.println("---");
        
        prog.work();
        prog.displayInfo();
        prog.code();
    }
}

最佳实践

1. 合理使用继承

java
// ✅ 好的继承关系:is-a 关系
class Dog extends Animal { }  // 狗是动物

// ❌ 不好的继承:不是 is-a 关系
// class Stack extends ArrayList { }  // 栈不是 ArrayList
// 应该使用组合而不是继承

2. 使用 protected 而不是 public

java
// ✅ 好的做法:使用 protected
public class Parent {
    protected String name;  // 子类可以访问
}

// ❌ 不好的做法:使用 public
public class Parent {
    public String name;  // 破坏了封装
}

3. 重写 equals 和 hashCode

java
@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    MyClass myClass = (MyClass) obj;
    return Objects.equals(field, myClass.field);
}

@Override
public int hashCode() {
    return Objects.hash(field);
}

下一步

掌握了继承后,可以继续学习:


💡 提示:继承是代码复用和扩展的重要机制,但要合理使用,避免过深的继承层次