🧬 Java 继承(Inheritance)完全指南
📖 继承的基本概念
什么是继承?
继承是面向对象编程的三大特性 之一,允许一个类(子类)基于另一个类(父类)构建,复用父类的属性和方法。
继承的核心思想
- 代码复用:子类继承父类的属性和方法
- 扩展功能:子类可以添加新的属性和方法
- 方法重写:子类可以重写父类的方法
- 多态基础:为多态提供支持
🎯 继承的基本语法
extends 关键字
java
// 父类(超类、基类)
class Animal {
String name;
int age;
void eat() {
System.out.println(name + "正在吃东西");
}
void sleep() {
System.out.println(name + "正在睡觉");
}
}
// 子类(派生类)
class Dog extends Animal { // 使用 extends 继承
// Dog 自动拥有 Animal 的所有属性和方法
// 子类可以添加新方法
void bark() {
System.out.println(name + "汪汪叫");
}
}
// 另一个子类
class Cat extends Animal {
void meow() {
System.out.println(name + "喵喵叫");
}
}
public class BasicInheritance {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "旺财";
dog.age = 3;
dog.eat(); // 继承自 Animal
dog.sleep(); // 继承自 Animal
dog.bark(); // Dog 自己的方法
System.out.println();
Cat cat = new Cat();
cat.name = "小花";
cat.age = 2;
cat.eat(); // 继承自 Animal
cat.sleep(); // 继承自 Animal
cat.meow(); // Cat 自己的方法
}
}
🔄 继承的特点
1. 单继承性
Java 只支持单继承,一个类只能有一个直接父类。
java
// ✅ 正确的单继承
class A {
void methodA() {
System.out.println("A的方法");
}
}
class B extends A {
void methodB() {
System.out.println("B的方法");
}
}
class C extends B {
void methodC() {
System.out.println("C的方法");
}
}
// ❌ 错误的多继承(Java不允许)
/*
class D extends A, B { // 编译错误
}
*/
public class SingleInheritance {
public static void main(String[] args) {
C obj = new C();
obj.methodA(); // 可以调用祖先类的方法
obj.methodB();
obj.methodC();
// 继承链:Object ← A ← B ← C
System.out.println("C的父类: " + obj.getClass().getSuperclass());
System.out.println("B的父类: " + obj.getClass().getSuperclass().getSuperclass());
}
}
2. 所有类的根类:Object
Java 中所有类都直接或间接继承自 Object 类。
java
class MyClass {
// 即使没有显式继承,也默认继承 Object
}
public class ObjectClassDemo {
public static void main(String[] args) {
MyClass obj = new MyClass();
// Object 类的方法都可以使用
System.out.println("字符串表示: " + obj.toString());
System.out.println("哈希码: " + obj.hashCode());
System.out.println("类名: " + obj.getClass());
// 常见的 Object 方法
Object obj1 = new Object();
Object obj2 = new Object();
System.out.println("\nObject 方法演示:");
System.out.println("equals: " + obj1.equals(obj2));
System.out.println("toString: " + obj1.toString());
System.out.println("getClass: " + obj1.getClass());
// 常用的 final 方法
System.out.println("wait, notify, notifyAll 用于线程同步");
}
}
3. 继承的访问权限
java
class Parent {
// 不同访问权限的成员
public String publicField = "public";
protected String protectedField = "protected";
String defaultField = "default"; // 包访问权限
private String privateField = "private";
public void show() {
// 父类中可以访问所有权限的成员
System.out.println("父类中访问:");
System.out.println("public: " + publicField);
System.out.println("protected: " + protectedField);
System.out.println("default: " + defaultField);
System.out.println("private: " + privateField);
}
}
class Child extends Parent {
public void accessTest() {
System.out.println("\n子类中访问:");
// 子类可以访问 public
System.out.println("public: " + publicField);
// 子类可以访问 protected
System.out.println("protected: " + protectedField);
// 同包时可以访问 default
System.out.println("default: " + defaultField);
// 子类不能访问 private
// System.out.println("private: " + privateField); // ❌ 编译错误
}
}
// 不同包中的子类
package other;
import Parent;
class DifferentPackageChild extends Parent {
public void accessTest() {
System.out.println("\n不同包子类中访问:");
// 可以访问 public
System.out.println("public: " + publicField);
// 可以访问 protected(子类权限)
System.out.println("protected: " + protectedField);
// 不能访问 default(不同包)
// System.out.println("default: " + defaultField); // ❌ 编译错误
// 不能访问 private
// System.out.println("private: " + privateField); // ❌ 编译错误
}
}
public class InheritanceAccess {
public static void main(String[] args) {
Child child = new Child();
child.show();
child.accessTest();
}
}
🔧 方法重写(Override)
1. 基本重写
java
class Vehicle {
protected String brand = "未知品牌";
// 父类方法
public void start() {
System.out.println("车辆启动");
}
public void stop() {
System.out.println("车辆停止");
}
public String getInfo() {
return "车辆品牌: " + brand;
}
}
class Car extends Vehicle {
private String model = "未知型号";
// 重写父类方法
@Override
public void start() {
System.out.println("汽车启动:插入钥匙,打火");
}
@Override
public void stop() {
System.out.println("汽车停止:踩刹车,熄火");
}
// 重写 getInfo 方法
@Override
public String getInfo() {
// 调用父类的方法
return super.getInfo() + ",型号: " + model;
}
// 新增方法
public void playMusic() {
System.out.println("播放音乐");
}
}
class ElectricCar extends Car {
private int batteryLevel = 100;
// 重写父类的方法
@Override
public void start() {
System.out.println("电动汽车启动:按下启动按钮");
}
@Override
public String getInfo() {
return super.getInfo() + ",电量: " + batteryLevel + "%";
}
// 新增方法
public void charge() {
System.out.println("正在充电...");
batteryLevel = 100;
}
}
public class MethodOverride {
public static void main(String[] args) {
System.out.println("=== 普通汽车 ===");
Car car = new Car();
car.brand = "丰田";
car.start();
car.stop();
System.out.println(car.getInfo());
car.playMusic();
System.out.println("\n=== 电动汽车 ===");
ElectricCar electricCar = new ElectricCar();
electricCar.brand = "特斯拉";
electricCar.start();
electricCar.stop();
System.out.println(electricCar.getInfo());
electricCar.playMusic(); // 继承自 Car
electricCar.charge();
}
}
2. 重写规则
java
class Parent {
// 可以被重写的方法
public void publicMethod() {
System.out.println("父类public方法");
}
protected void protectedMethod() {
System.out.println("父类protected方法");
}
// 不能被重写的方法
private void privateMethod() {
System.out.println("父类private方法");
}
public final void finalMethod() {
System.out.println("父类final方法");
}
public static void staticMethod() {
System.out.println("父类static方法");
}
}
class Child extends Parent {
// ✅ 正确:重写public方法(访问权限可以相同或更宽松)
@Override
public void publicMethod() {
System.out.println("子类重写的public方法");
}
// ✅ 正确:protected可以重写为public
@Override
public void protectedMethod() {
System.out.println("子类重写的protected方法(改为public)");
}
// ❌ 错误:不能重写private方法
// @Override
// private void privateMethod() { } // 编译错误
// ❌ 错误:不能重写final方法
// @Override
// public final void finalMethod() { } // 编译错误
// ❌ 错误:不能重写static方法(这是隐藏,不是重写)
public static void staticMethod() {
System.out.println("子类static方法(隐藏父类)");
}
// ❌ 错误:访问权限不能更严格
/*
@Override
void publicMethod() { // 改为默认权限,编译错误
System.out.println("错误的重写");
}
*/
}
public class OverrideRules {
public static void main(String[] args) {
Child child = new Child();
child.publicMethod();
child.protectedMethod();
// 静态方法调用(属于类,不是对象)
Parent.staticMethod();
Child.staticMethod();
// 验证重写规则
System.out.println("\n重写规则总结:");
System.out.println("1. 方法名、参数列表必须相同");
System.out.println("2. 返回值类型相同或是子类");
System.out.println("3. 访问权限不能比父类更严格");
System.out.println("4. 不能重写private、final、static方法");
System.out.println("5. 抛出的异常不能比父类更多或更通用");
}
}
3. @Override 注解
java
class Base {
public void display() {
System.out.println("Base display");
}
public void show(String message) {
System.out.println("Base show: " + message);
}
}
class Derived extends Base {
// 使用 @Override 注解:明确表示这是重写
@Override
public void display() {
System.out.println("Derived display");
}
// @Override 可以帮助发现错误
/*
@Override
public void Display() { // 方法名写错了,编译器会报错
System.out.println("拼写错误");
}
*/
/*
@Override
public void show() { // 参数列表不同,不是重写,编译器报错
System.out.println("缺少参数");
}
*/
@Override
public void show(String msg) { // 正确重写
System.out.println("Derived show: " + msg);
}
// 重载(Overload),不是重写
public void show(String msg, int times) {
for (int i = 0; i < times; i++) {
System.out.println("Derived show: " + msg);
}
}
}
public class OverrideAnnotation {
public static void main(String[] args) {
Derived obj = new Derived();
obj.display();
obj.show("Hello");
obj.show("Hello", 3);
System.out.println("\n@Override 注解的好处:");
System.out.println("1. 提高代码可读性");
System.out.println("2. 编译器检查重写是否正确");
System.out.println("3. 避免拼写错误或参数错误");
System.out.println("4. 方便IDE进行重构和分析");
}
}
🔄 super 关键字
1. 调用父类构造器
java
class Person {
private String name;
private int age;
// 父类构造器
public Person() {
this.name = "未知";
this.age = 0;
System.out.println("Person无参构造器");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person有参构造器");
}
public String getInfo() {
return "姓名: " + name + ", 年龄: " + age;
}
}
class Student extends Person {
private String studentId;
private String school;
// 子类构造器必须调用父类构造器
public Student() {
super(); // 调用父类无参构造器(可省略,编译器会自动添加)
this.studentId = "未分配";
this.school = "未知学校";
System.out.println("Student无参构造器");
}
public Student(String name, int age, String studentId, String school) {
super(name, age); // 必须放在第一行
this.studentId = studentId;
this.school = school;
System.out.println("Student有参构造器");
}
// 错误示例:super() 不是第一句
/*
public Student(String id) {
System.out.println("初始化..."); // ❌ 编译错误
super(); // super() 必须在第一行
this.studentId = id;
}
*/
@Override
public String getInfo() {
// 调用父类的方法
return super.getInfo() + ", 学号: " + studentId + ", 学校: " + school;
}
// 访问父类属性(如果权限允许)
public void showParentInfo() {
// System.out.println(name); // ❌ 不能直接访问父类private属性
System.out.println(getInfo()); // ✅ 通过方法访问
}
}
public class SuperConstructor {
public static void main(String[] args) {
System.out.println("=== 创建学生1 ===");
Student s1 = new Student();
System.out.println(s1.getInfo());
System.out.println("\n=== 创建学生2 ===");
Student s2 = new Student("张三", 20, "2023001", "清华大学");
System.out.println(s2.getInfo());
s2.showParentInfo();
}
}
2. 访问父类成员
java
class Animal {
protected String name = "动物";
public void eat() {
System.out.println(name + "在吃东西");
}
public void sleep() {
System.out.println(name + "在睡觉");
}
}
class Bird extends Animal {
private String name = "小鸟"; // 隐藏父类的name
@Override
public void eat() {
System.out.println(name + "在吃虫子");
}
public void show() {
System.out.println("\n在Bird类中:");
// 访问子类的name
System.out.println("this.name = " + this.name);
// 访问父类的name
System.out.println("super.name = " + super.name);
// 调用子类的方法
this.eat();
// 调用父类的方法
super.eat();
super.sleep();
// 访问父类被重写的方法
System.out.println("\n通过super访问被重写的方法:");
super.eat(); // 调用父类的eat
}
// 演示方法重写
@Override
public void sleep() {
System.out.println(name + "在鸟巢睡觉");
// 可以在重写方法中调用父类方法
super.sleep(); // 调用父类的sleep
System.out.println(name + "睡醒了");
}
}
public class SuperMember {
public static void main(String[] args) {
Bird bird = new Bird();
bird.show();
System.out.println("\n=== 测试重写方法 ===");
bird.sleep();
}
}
🏗️ 构造器调用链
java
class Grandparent {
public Grandparent() {
System.out.println("1. Grandparent构造器");
}
public Grandparent(String message) {
System.out.println("1. Grandparent构造器: " + message);
}
}
class Parent extends Grandparent {
public Parent() {
// 这里会自动调用 super()
System.out.println("2. Parent构造器");
}
public Parent(String message) {
super("来自Parent的消息"); // 显式调用父类构造器
System.out.println("2. Parent构造器: " + message);
}
}
class Child extends Parent {
public Child() {
// 这里会自动调用 super()
System.out.println("3. Child构造器");
}
public Child(String message) {
super("来自Child的消息"); // 调用父类构造器
System.out.println("3. Child构造器: " + message);
}
public Child(int number) {
this("带参数的Child"); // 调用本类其他构造器
System.out.println("3. Child构造器(数字): " + number);
}
}
public class ConstructorChain {
public static void main(String[] args) {
System.out.println("=== 创建Child对象(无参)===");
Child c1 = new Child();
System.out.println("\n=== 创建Child对象(有参)===");
Child c2 = new Child("测试");
System.out.println("\n=== 创建Child对象(数字)===");
Child c3 = new Child(100);
/*
输出结果:
=== 创建Child对象(无参)===
1. Grandparent构造器
2. Parent构造器
3. Child构造器
=== 创建Child对象(有参)===
1. Grandparent构造器: 来自Parent的消息
2. Parent构造器: 来自Child的消息
3. Child构造器: 测试
=== 创建Child对象(数字)===
1. Grandparent构造器: 来自Parent的消息
2. Parent构造器: 来自Child的消息
3. Child构造器: 带参数的Child
3. Child构造器(数字): 100
*/
System.out.println("\n构造器调用规则:");
System.out.println("1. 构造器第一行必须是 this() 或 super()");
System.out.println("2. 如果没有显式调用,编译器会自动添加 super()");
System.out.println("3. this() 和 super() 不能同时存在");
System.out.println("4. 构造器调用形成一条链,最终会调用到 Object 的构造器");
}
}
⚠️ 继承的注意事项
1. 谨慎使用继承
java
// ❌ 错误的继承使用:为了复用代码而滥用继承
class Engine {
void start() {
System.out.println("引擎启动");
}
}
// Car 和 Engine 不是 "is-a" 关系,而是 "has-a" 关系
/*
class Car extends Engine { // 错误:汽车不是一种引擎
void drive() {
System.out.println("汽车行驶");
}
}
*/
// ✅ 正确的做法:使用组合
class Car {
private Engine engine; // 组合:汽车有一个引擎
public Car() {
this.engine = new Engine();
}
void drive() {
engine.start(); // 调用引擎的方法
System.out.println("汽车行驶");
}
}
// ✅ 正确的继承:符合 "is-a" 关系
class Vehicle {
void move() {
System.out.println("交通工具移动");
}
}
class Truck extends Vehicle { // 正确:卡车是一种交通工具
@Override
void move() {
System.out.println("卡车在路上行驶");
}
}
class Boat extends Vehicle { // 正确:船是一种交通工具
@Override
void move() {
System.out.println("船在水上航行");
}
}
public class InheritanceDesign {
public static void main(String[] args) {
System.out.println("继承设计原则:");
System.out.println("1. 符合 is-a 关系才使用继承");
System.out.println("2. 优先使用组合而不是继承");
System.out.println("3. 避免过深的继承层次(通常不超过3层)");
System.out.println("4. 考虑使用接口实现多继承的效果");
Car car = new Car();
car.drive();
}
}
2. final 关键字与继承
java
// final 类:不能被继承
final class FinalClass {
public void show() {
System.out.println("FinalClass的方法");
}
}
// ❌ 错误:不能继承final类
/*
class SubClass extends FinalClass { // 编译错误
}
*/
class NormalClass {
// final 方法:不能被子类重写
public final void finalMethod() {
System.out.println("这个方法不能重写");
}
// 普通方法:可以重写
public void normalMethod() {
System.out.println("这个方法可以重写");
}
}
class SubNormalClass extends NormalClass {
/*
// ❌ 错误:不能重写final方法
@Override
public void finalMethod() {
System.out.println("尝试重写");
}
*/
// ✅ 正确:可以重写普通方法
@Override
public void normalMethod() {
System.out.println("重写后的方法");
}
}
public class FinalInheritance {
public static void main(String[] args) {
System.out.println("final 关键字的作用:");
System.out.println("1. final 类:不能被继承(如 String、Integer)");
System.out.println("2. final 方法:不能被子类重写");
System.out.println("3. final 变量:常量,不能修改");
System.out.println("\n使用 final 的好处:");
System.out.println("1. 提高性能(编译器优化)");
System.out.println("2. 保证安全性(防止修改)");
System.out.println("3. 设计意图明确(禁止扩展)");
FinalClass obj = new FinalClass();
obj.show();
}
}
💡 继承的最佳实践
1. 抽象类和继承
java
// 抽象类:不能实例化,用于定义模板
abstract class Employee {
private String name;
private String id;
public Employee(String name, String id) {
this.name = name;
this.id = id;
}
// 抽象方法:必须由子类实现
public abstract double calculateSalary();
// 具体方法:子类可以直接使用或重写
public String getInfo() {
return "员工: " + name + " (ID: " + id + ")";
}
// 模板方法模式
public final void showSalary() {
System.out.println(getInfo());
System.out.println("月薪: " + calculateSalary());
}
}
// 具体子类
class FullTimeEmployee extends Employee {
private double monthlySalary;
public FullTimeEmployee(String name, String id, double monthlySalary) {
super(name, id);
this.monthlySalary = monthlySalary;
}
@Override
public double calculateSalary() {
return monthlySalary;
}
}
class PartTimeEmployee extends Employee {
private double hourlyRate;
private int hoursWorked;
public PartTimeEmployee(String name, String id, double hourlyRate, int hours) {
super(name, id);
this.hourlyRate = hourlyRate;
this.hoursWorked = hours;
}
@Override
public double calculateSalary() {
return hourlyRate * hoursWorked;
}
}
public class AbstractClassDemo {
public static void main(String[] args) {
// ❌ 错误:不能实例化抽象类
// Employee emp = new Employee("张三", "001");
// ✅ 正确:创建具体子类的对象
Employee emp1 = new FullTimeEmployee("张三", "FT001", 8000.0);
Employee emp2 = new PartTimeEmployee("李四", "PT001", 50.0, 120);
System.out.println("=== 员工薪资 ===");
emp1.showSalary();
emp2.showSalary();
System.out.println("\n抽象类的优点:");
System.out.println("1. 定义通用模板和行为规范");
System.out.println("2. 强制子类实现特定方法");
System.out.println("3. 代码复用和扩展性");
System.out.println("4. 支持模板方法模式");
}
}
📊 继承总结表
| 特性 | 说明 |
|---|---|
| 语法 | class SubClass extends SuperClass |
| 单继承 | Java 只支持单继承 |
| 所有类根 | 所有类继承自 Object |
| 访问权限 | 子类可以访问父类的 public、protected、同包default |
| 构造器 | 子类必须调用父类构造器(显式或隐式) |
| 方法重写 | 子类可以重写父类非private、非final、非static方法 |
| super关键字 | 访问父类成员、调用父类构造器 |
| 向上转型 | 子类对象可以赋值给父类引用 |
| 动态绑定 | 实例方法调用在运行时确定 |
| final类 | 不能被继承 |
| final方法 | 不能被子类重写 |
| 抽象类 | 不能实例化,用于定义模板 |
| 继承层次 | 不宜过深(通常≤3层) |
🎓 继承最佳实践总结
- 符合 is-a 关系:子类应该是父类的特殊类型
- 优先使用组合:除非需要多态,否则优先考虑组合
- 避免深层继承:继承层次不宜过深(≤3层)
- 合理使用 final:明确设计意图,防止不必要的扩展
- 使用抽象类:为相关类提供通用模板
- 使用接口:实现多重继承,定义行为契约
- 方法访问权限:从严格到宽松,避免过度暴露
- 构造函数设计:合理设计构造器链,确保对象正确初始化
记住:继承是强耦合关系 ,要谨慎使用。在面向对象设计中,组合优于继承(Composition over Inheritance)是一个重要原则!