在 Java 的面向对象世界中,继承就像现实世界的 "父子关系" 一样,让类与类之间建立起自然的层级联系。当你需要创建 "学生" 和 "教师" 类时,不必重复编写 "姓名"、"年龄" 等共同属性,通过继承 "人" 类就能轻松实现代码复用。这种特性不仅减少了重复劳动,更让系统架构呈现出清晰的逻辑层次。
一、继承的基本语法与本质
Java 通过extends
关键字实现继承,子类(subclass)将获得父类(superclass)的非私有成员:
// 父类
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + "正在吃饭");
}
public String getName() {
return name;
}
// getter和setter省略
}
// 子类继承父类
public class Student extends Person {
private String studentId;
private String major;
// 子类构造器必须调用父类构造器
public Student(String name, int age, String studentId, String major) {
super(name, age); // 调用父类构造器
this.studentId = studentId;
this.major = major;
}
// 子类特有方法
public void study() {
System.out.println(getName() + "正在学习" + major + "专业");
}
}
继承的本质是 "is-a" 关系:Student is a Person,这种语义约束确保了继承关系的合理性。Java 只支持单继承(一个类只能有一个直接父类),但通过接口可以实现类似多继承的效果。
二、方法重写:继承中的多态基础
子类可以重写(override)父类的方法,实现符合自身特性的行为:
public class Teacher extends Person {
private String subject;
public Teacher(String name, int age, String subject) {
super(name, age);
this.subject = subject;
}
// 重写父类的eat方法
@Override
public void eat() {
System.out.println(getName() + "快速地吃饭,因为要赶去上课");
}
// 新增特有方法
public void teach() {
System.out.println(getName() + "正在教授" + subject + "课程");
}
}
方法重写需遵循 "两同两小一大" 原则:
- 方法名和参数列表相同
- 返回值类型小于等于父类(协变返回类型)
- 抛出异常小于等于父类
- 访问权限大于等于父类
@Override
注解可强制编译器检查重写是否正确,是最佳实践。
三、super 关键字:连接父类的桥梁
super
关键字用于访问父类的成员,主要有三种用法:
- 调用父类构造器:
public class GraduateStudent extends Student { private String researchDirection; public GraduateStudent(String name, int age, String studentId, String major, String researchDirection) { super(name, age, studentId, major); // 必须是子类构造器第一句 this.researchDirection = researchDirection; } }
-
调用父类方法:
@Override public void study() { super.study(); // 调用父类的study方法 System.out.println("同时进行" + researchDirection + "研究"); }
-
访问父类属性:
public class Child extends Parent { private String name; public void printNames() { System.out.println("子类name: " + this.name); System.out.println("父类name: " + super.name); } }
四、final 关键字与继承控制
final
关键字可限制继承行为:
- final 类:不能被继承
public final class String { // 源码不能被继承 }
- final 方法:不能被重写
public class Parent { public final void criticalOperation() { // 核心逻辑,不允许子类修改 } }
- final 变量:继承中保持不变
public class Constants { public static final double PI = 3.1415926; }
五、实战案例:构建员工管理系统
// 顶层抽象类
public abstract class Employee {
private String id;
private String name;
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
public abstract double calculateSalary(); // 抽象方法
// 共性方法
public void printInfo() {
System.out.println("员工ID: " + id + ", 姓名: " + name);
}
}
// 全职员工
public class FullTimeEmployee extends Employee {
private double monthlySalary;
public FullTimeEmployee(String id, String name, double monthlySalary) {
super(id, name);
this.monthlySalary = monthlySalary;
}
@Override
public double calculateSalary() {
return monthlySalary;
}
}
// 兼职员工
public class PartTimeEmployee extends Employee {
private double hourlyRate;
private int hoursWorked;
public PartTimeEmployee(String id, String name, double hourlyRate, int hoursWorked) {
super(id, name);
this.hourlyRate = hourlyRate;
this.hoursWorked = hoursWorked;
}
@Override
public double calculateSalary() {
return hourlyRate * hoursWorked;
}
}
// 使用示例
public class EmployeeManager {
public static void main(String[] args) {
Employee ftEmp = new FullTimeEmployee("1001", "张三", 8000);
Employee ptEmp = new PartTimeEmployee("2001", "李四", 50, 80);
ftEmp.printInfo();
System.out.println("月薪: " + ftEmp.calculateSalary());
ptEmp.printInfo();
System.out.println("时薪: " + ptEmp.calculateSalary());
}
}
这个设计通过继承实现了员工类型的清晰划分,同时利用多态简化了薪资计算逻辑。
继承是 Java 中实现代码复用的强大机制,但也容易被滥用。优秀的继承设计应该满足:语义上的 is-a 关系、遵循合理的抽象层次。
思考:如何利用继承和多态设计一个图形绘制系统,支持圆形、矩形、三角形等多种图形的面积计算和绘制?欢迎在评论区分享你的思路。