一、继承的基本概念

继承是面向对象编程的三大特性之一(封装、继承、多态),它允许我们基于已有的类创建新的类。在Java中,继承通过extends关键字实现。

1.1 为什么需要继承?

  • 代码复用:避免重复编写相同的代码
  • 层次结构:建立类之间的层次关系
  • 扩展性:在不修改原有类的基础上添加新功能

1.2 继承的语法

// 父类(基类)
class Animal {
    String name;
    int age;
    
    void eat() {
        System.out.println(name + "正在吃东西");
    }
    
    void sleep() {
        System.out.println(name + "正在睡觉");
    }
}

// 子类(派生类)
class Dog extends Animal {
    String breed;  // 子类特有的属性
    
    void bark() {
        System.out.println(name + "汪汪叫");
    }
}

1.3 继承的特点

  • Java只支持单继承(一个类只能有一个直接父类)
  • 子类继承父类的所有非私有成员(属性和方法)
  • 子类可以添加自己的新成员
  • 构造方法不能被继承

二、方法重写(Override)

方法重写是子类重新定义父类中已有方法的行为,以满足子类的特定需求。

2.1 方法重写的规则

  1. 方法签名必须相同:方法名、参数列表必须完全一致
  2. 返回类型相同或是其子类(协变返回类型)
  3. 访问权限不能更严格:子类方法的访问权限不能低于父类
  4. 不能重写private、final、static方法
  5. 抛出的异常不能更宽泛

2.2 @Override注解

使用@Override注解可以帮助编译器检查是否正确重写了父类方法,并提高代码可读性。

class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
    
    public Animal getAnimal() {
        return new Animal();
    }
}

class Cat extends Animal {
    // 正确重写
    @Override
    public void makeSound() {
        System.out.println("喵喵叫");
    }
    
    // 协变返回类型示例
    @Override
    public Cat getAnimal() {
        return new Cat();
    }
}

三、继承与方法重写的实战示例

3.1 完整的继承体系示例

// 父类:员工
class Employee {
    private String name;
    private double baseSalary;
    
    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }
    
    public double calculateSalary() {
        return baseSalary;
    }
    
    public void displayInfo() {
        System.out.println("员工姓名:" + name);
        System.out.println("基本工资:" + baseSalary);
    }
}

// 子类:经理(有奖金)
class Manager extends Employee {
    private double bonus;
    
    public Manager(String name, double baseSalary, double bonus) {
        super(name, baseSalary);  // 调用父类构造方法
        this.bonus = bonus;
    }
    
    // 重写计算工资的方法
    @Override
    public double calculateSalary() {
        return super.calculateSalary() + bonus;  // 调用父类方法并添加奖金
    }
    
    // 重写显示信息的方法
    @Override
    public void displayInfo() {
        super.displayInfo();  // 先显示父类信息
        System.out.println("奖金:" + bonus);
        System.out.println("总工资:" + calculateSalary());
    }
    
    // 经理特有的方法
    public void holdMeeting() {
        System.out.println("经理正在主持会议");
    }
}

// 子类:开发人员(有项目奖金)
class Developer extends Employee {
    private int completedProjects;
    private static final double PROJECT_BONUS = 1000.0;
    
    public Developer(String name, double baseSalary, int completedProjects) {
        super(name, baseSalary);
        this.completedProjects = completedProjects;
    }
    
    @Override
    public double calculateSalary() {
        return super.calculateSalary() + (completedProjects * PROJECT_BONUS);
    }
    
    @Override
    public void displayInfo() {
        super.displayInfo();
        System.out.println("完成项目数:" + completedProjects);
        System.out.println("项目奖金:" + (completedProjects * PROJECT_BONUS));
        System.out.println("总工资:" + calculateSalary());
    }
    
    public void writeCode() {
        System.out.println("开发人员正在编写代码");
    }
}

3.2 测试代码

public class InheritanceDemo {
    public static void main(String[] args) {
        // 创建普通员工
        Employee emp1 = new Employee("张三", 5000);
        System.out.println("=== 普通员工 ===");
        emp1.displayInfo();
        System.out.println();
        
        // 创建经理
        Manager mgr = new Manager("李四", 8000, 3000);
        System.out.println("=== 经理 ===");
        mgr.displayInfo();
        mgr.holdMeeting();
        System.out.println();
        
        // 创建开发人员
        Developer dev = new Developer("王五", 6000, 5);
        System.out.println("=== 开发人员 ===");
        dev.displayInfo();
        dev.writeCode();
        System.out.println();
        
        // 多态演示
        System.out.println("=== 多态演示 ===");
        Employee[] employees = {emp1, mgr, dev};
        
        for (Employee emp : employees) {
            System.out.println("员工类型:" + emp.getClass().getSimpleName());
            System.out.println("应发工资:" + emp.calculateSalary());
            System.out.println("---");
        }
    }
}

四、继承中的关键概念

4.1 super关键字

  • super():调用父类构造方法(必须是子类构造方法的第一条语句)
  • super.成员:访问父类的成员(属性和方法)
class Parent {
    String message = "父类消息";
    
    void show() {
        System.out.println("父类方法");
    }
}

class Child extends Parent {
    String message = "子类消息";
    
    void display() {
        System.out.println(super.message);  // 访问父类属性
        System.out.println(this.message);   // 访问子类属性
        super.show();                       // 调用父类方法
    }
}

4.2 构造方法的继承

class Vehicle {
    private String brand;
    
    public Vehicle(String brand) {
        this.brand = brand;
        System.out.println("Vehicle构造方法被调用");
    }
}

class Car extends Vehicle {
    private int doors;
    
    public Car(String brand, int doors) {
        super(brand);  // 必须调用父类构造方法
        this.doors = doors;
        System.out.println("Car构造方法被调用");
    }
}

4.3 final关键字与继承

  • final class:类不能被继承
  • final method:方法不能被重写
  • final variable:变量值不能被修改
final class FinalClass {  // 这个类不能被继承
    final double PI = 3.14159;  // 常量
    
    final void finalMethod() {  // 这个方法不能被重写
        System.out.println("这是最终方法");
    }
}

五、方法重写 vs 方法重载

特性 方法重写 (Override) 方法重载 (Overload)
发生位置 父子类之间 同一个类中
方法签名 必须完全相同 必须不同(参数类型、个数、顺序)
返回类型 相同或协变 可以不同
访问权限 不能更严格 可以不同
抛出异常 不能更宽泛 可以不同
class OverloadVsOverride {
    // 方法重载示例
    void display(int num) {
        System.out.println("整数:" + num);
    }
    
    void display(String str) {
        System.out.println("字符串:" + str);
    }
    
    void display(int num, String str) {
        System.out.println("整数:" + num + ",字符串:" + str);
    }
}

class ParentClass {
    void show() {
        System.out.println("父类方法");
    }
}

class ChildClass extends ParentClass {
    // 方法重写示例
    @Override
    void show() {
        System.out.println("子类重写的方法");
    }
}

六、最佳实践与常见问题

6.1 继承设计原则

  1. 里氏替换原则:子类对象应该能够替换父类对象而不影响程序正确性
  2. 优先使用组合而非继承:除非有明显的"is-a"关系
  3. 避免过深的继承层次:一般不超过3层
  4. 使用抽象类和接口:定义规范,实现多态

6.2 常见错误

class CommonMistakes {
    // 错误1:试图重写private方法
    class Parent {
        private void method() {}  // 子类无法重写
    }
    
    // 错误2:缩小访问权限
    class Child extends Parent {
        // @Override  // 编译错误
        // private void method() {}  // 不能把public改为private
    }
    
    // 错误3:忘记调用super()
    class Vehicle {
        Vehicle(String name) {}
    }
    
    class Car extends Vehicle {
        Car() {
            // 编译错误:必须调用super(name)
        }
    }
}

6.3 实际应用场景

  1. GUI框架:Swing/AWT中的组件继承
  2. 集合框架:ArrayList继承AbstractList
  3. 异常处理:自定义异常继承Exception
  4. 企业应用:DAO层、Service层的通用基类

七、总结

继承和方法重写是Java面向对象编程的核心概念,它们共同实现了代码复用和多态性。正确使用继承可以:

  • 减少代码冗余
  • 提高代码可维护性
  • 实现灵活的扩展机制
  • 支持运行时多态

记住关键点:

  1. 继承使用extends关键字,Java只支持单继承
  2. 方法重写需要遵守"两同两小一大"原则
  3. 使用@Override注解提高代码质量
  4. 合理使用super关键字访问父类成员
  5. 遵循面向对象设计原则,避免滥用继承

通过本文的示例代码和详细解释,你应该能够掌握Java中继承和方法重写的核心概念,并在实际项目中正确应用这些技术。

更多推荐