Appearance
🔗 继承
继承概述
继承(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 的用途
- 调用父类构造方法:
super(参数) - 调用父类方法:
super.方法名() - 访问父类成员变量:
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)
重写规则
- 方法名、参数列表必须相同
- 返回类型必须相同或是父类返回类型的子类型
- 访问权限不能比父类更严格
- 不能抛出比父类更多的异常(或父类异常的子类)
重写示例
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();继承的优缺点
优点
- 代码复用:子类可以复用父类的代码
- 扩展性:子类可以添加新功能
- 多态支持:为实现多态提供基础
- 维护性:修改父类影响所有子类
缺点
- 耦合度高:子类与父类紧密耦合
- 单继承限制:Java 只支持单继承
- 设计复杂:继承层次过深会难以理解
完整示例
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);
}下一步
掌握了继承后,可以继续学习:
💡 提示:继承是代码复用和扩展的重要机制,但要合理使用,避免过深的继承层次
