Java面向对象编程:深入理解继承与方法重写
·
一、继承的基本概念
继承是面向对象编程的三大特性之一(封装、继承、多态),它允许我们基于已有的类创建新的类。在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 方法重写的规则
- 方法签名必须相同:方法名、参数列表必须完全一致
- 返回类型相同或是其子类(协变返回类型)
- 访问权限不能更严格:子类方法的访问权限不能低于父类
- 不能重写private、final、static方法
- 抛出的异常不能更宽泛
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 继承设计原则
- 里氏替换原则:子类对象应该能够替换父类对象而不影响程序正确性
- 优先使用组合而非继承:除非有明显的"is-a"关系
- 避免过深的继承层次:一般不超过3层
- 使用抽象类和接口:定义规范,实现多态
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 实际应用场景
- GUI框架:Swing/AWT中的组件继承
- 集合框架:ArrayList继承AbstractList
- 异常处理:自定义异常继承Exception
- 企业应用:DAO层、Service层的通用基类
七、总结
继承和方法重写是Java面向对象编程的核心概念,它们共同实现了代码复用和多态性。正确使用继承可以:
- 减少代码冗余
- 提高代码可维护性
- 实现灵活的扩展机制
- 支持运行时多态
记住关键点:
- 继承使用
extends关键字,Java只支持单继承 - 方法重写需要遵守"两同两小一大"原则
- 使用
@Override注解提高代码质量 - 合理使用
super关键字访问父类成员 - 遵循面向对象设计原则,避免滥用继承
通过本文的示例代码和详细解释,你应该能够掌握Java中继承和方法重写的核心概念,并在实际项目中正确应用这些技术。
更多推荐


所有评论(0)