跳到主要内容

创建日期:2026-09-08 | 最近更新:2026-09-08 主线 JDK 11(本机实测可跑);record(JDK 16+)标注不实测。

Java 复习手册 3:继承、接口与多态

上一篇会「造单个类」了。这篇解决「类与类之间怎么关联」——继承(复用代码)、接口(定义能力)、多态(同一调用,不同表现)。这是 Java 面向对象真正的分水岭,也是你以前「学了又忘」的重灾区,放慢点。

1. 继承:子类复用父类,extends

// 父类
public class Animal {
protected String name; // protected:子类能访问

public Animal(String name) { this.name = name; }

public void speak() { System.out.println("..."); }
}

// 子类:extends 父类
public class Dog extends Animal {
public Dog(String name) { super(name); } // super(...) = 调父类构造器(必须是子类构造器第一句)

@Override // 覆写:重新实现父类方法
public void speak() {
System.out.println(name + ":汪汪");
}
}
Animal a = new Dog("旺财");
a.speak(); // 运行时调用的是 Dog 的覆写版 → 「旺财:汪汪」这就是多态

必须记住的三句话

  1. Java 是单继承:一个类只能 extends 一个父类(想要多种能力 → 用接口,见下);
  2. 子类构造器第一行super(...) 调父类构造器;父类有带参构造器而你没写 super → 编译报错;
  3. 覆写加 @Override(编译器帮检查签名),父类方法想让子类能覆写就别 final

2. final:三个「锁死」用法(别和 static 混)

位置作用
final class X这个类不能被继承(如 String
final int x = 1变量只能赋值一次(常量)
final 方法子类不能覆写

结合上篇:public static final double PI = 3.14; = 「属于类的只读常量」。

3. 抽象类:只定规矩,不做实现

当父类「有公共字段和部分方法,但某个方法说不清怎么实现」时,把它声明成抽象

public abstract class Shape {
protected String color;

public Shape(String color) { this.color = color; }

public abstract double area(); // 只有声明,没有方法体,交给子类实现
}

public class Circle extends Shape {
private double r;
public Circle(String color, double r) { super(color); this.r = r; }

@Override
public double area() { return Math.PI * r * r; } // 子类必须实现抽象方法
}
  • abstract不能 new(没实现完整),只能被继承;
  • 子类必须实现所有抽象方法,否则子类也得是 abstract;
  • 适用:几个类是同一个物种(is-a),共享状态 + 有共同但不完整的行为。

4. 接口:只定义「会什么」,不管「是什么」

接口比抽象类更「纯」:只列方法签名,连字段都没有(常量除外),谁实现谁就得会这些能力。

public interface Flyable {
void fly(); // 默认 public abstract,方法体没有

default void log() { // default 方法:接口里也能给默认实现(可选)
System.out.println("飞行动作已记录");
}
}

public class Bird extends Animal implements Flyable { // 先 extends,再 implements,可多个
public Bird(String name) { super(name); }

@Override public void speak() { System.out.println("啾啾"); }
@Override public void fly() { System.out.println(name + " 飞起来了"); }
}

抽象类 vs 接口(高频面试 + 高频遗忘)

抽象类接口
关键词abstract classinterface
继承数量只能 extends 一个可以 implements 多个
字段可以有实例字段基本只能常量(JDK9+ 可私有方法)
定位一种」(is-a),共享状态做某事」(has ability)
选谁共享代码/状态 → 抽象类定义能力契约 → 接口(现代 Java 更偏爱接口)

5. 多态:把对象当父类型/接口用

多态 = 同一个引用类型,实际指向不同子类对象,调用同名方法走各自实现

Animal[] animals = { new Dog("旺财"), new Bird("小雀") };
for (Animal a : animals) {
a.speak(); // 各叫各的 → 汪 / 啾啾
if (a instanceof Bird b) { // instanceof 判断真实类型;JDK16+ 可这样绑定变量
b.fly();
}
}
  • 向上转型Animal a = new Dog(...) —— 子类当父类用,天然允许;
  • 声明成 Animal/Flyable,代码只依赖「抽象」,加新子类不用改调用方 → 这就是面向接口编程的意义;
  • instanceof 判断后要强转才能用子类特有方法(((Dog) a).watchDoor())。

6. 每个类都该会覆写的三个方法

@Override
public String toString() { // 打印对象时的文字,默认是 类名@地址
return "Dog(" + name + ")";
}

@Override
public boolean equals(Object o) { // 定义「两个对象什么时候相等」
if (this == o) return true;
if (!(o instanceof Dog that)) return false;
return this.name.equals(that.name);
}

@Override
public int hashCode() { // 跟 equals 配套(放进 HashSet/HashMap 必需)
return name.hashCode();
}

口诀:改 equals 必改 hashCode,否则对象放进 Set/Map 会「看着相等却找不着」。

想少写样板?现代 Java 用 record(JDK 16+):record Point(int x, int y) {} 自动给你构造器 + equals/hashCode/toString——等你会搭项目后再回来享受它。

动手 3 分钟

Shape(abstract) + Circle/Rectangle 两个子类,写个方法打印面积总和;再给 Dog 覆写 toString 看效果。

自测

  1. 单继承指什么?怎么做到「同时是 A 又能飞」?
  2. 覆写和重载的区别?
  3. 抽象类能不能 new?为什么?
  4. 接口里的方法默认是什么修饰符?
  5. equalshashCode 为什么要一起改?