单继承

public class Animal {
    protected String name;
    public Animal(String name) { this.name = name; }
    public void sleep() { System.out.println(name + " sleeps"); }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);                  // 调父构造
    }

    public void bark() {
        System.out.println(name + " barks!");
    }
}

var d = new Dog("Rex");
d.sleep();    // 继承
d.bark();     // 自己的

extends 关键字。Java 单继承——一个类只一个父类。但可以实现多个接口(第 11 篇)。

super 调父

public class Dog extends Animal {
    public Dog(String name) {
        super(name);                  // 父构造(必须第一行)
    }

    @Override
    public void sleep() {
        super.sleep();                // 父方法
        System.out.println("(snoring)");
    }
}

@Override 强制声明

public class Cat extends Animal {
    @Override
    public void sleep() {
        ...
    }
}

@Override 注解 = "我打算重写父方法"。如果拼错或父类没这方法 → 编译错,避免低级失误。永远写

多态

Animal a = new Dog("Rex");
a.sleep();        // 调 Dog 的(不是 Animal 的)
a.bark();         // ❌ 编译错:Animal 类型没 bark

声明类型 Animal、实际类型 Dog——调方法走实际类型。这是面向对象的多态。

向下转换:

if (a instanceof Dog d) {       // 模式(Java 16+)
    d.bark();
}

// 老写法
if (a instanceof Dog) {
    Dog d = (Dog) a;
    d.bark();
}

abstract class

public abstract class Shape {
    public abstract double area();           // 没实现,强制子类提供

    public void describe() {                  // 普通方法
        System.out.println("Area = " + area());
    }
}

public class Circle extends Shape {
    private double radius;
    public Circle(double r) { radius = r; }
    @Override
    public double area() { return Math.PI * radius * radius; }
}

// new Shape() ❌ 抽象类不能实例化
var c = new Circle(5);
c.describe();

abstract class:不能实例化、可以有抽象方法。 abstract method:只签名没实现,子类必须 override。

final

public final class Config { ... }            // 类:不能继承

public class Animal {
    public final void name() { ... }         // 方法:子类不能 override
}

final class:禁止继承(例:StringInteger)。 final method:禁止重写。

经验:默认 final 是好实践——避免误继承。需要扩展的类显式 unfinal。

protected

public class Animal {
    protected int age;     // 子类 + 同包能访问,外部不能
}

public class Dog extends Animal {
    public void check() {
        if (age < 0) ...    // ✅ 能用
    }
}

Object 是根

Object o = 42;       // int 装箱后是 Integer,都继承 Object
o = "hello";
o = new Person();

// Object 自带方法
o.toString();
o.getClass();
o.hashCode();
o.equals(other);

所有类隐式继承 Object。重写 toString / equals / hashCode 是日常。

接口 vs 抽象类

接口 抽象类
多继承 ✅ 多实现 ❌ 单继承
字段 只 static final("常量") 任意
默认方法 ✅(Java 8+)
构造函数
状态

经验:

  • 纯契约 / 多种实现 → 接口
  • 共享状态 + 部分扩展点 → 抽象类
  • 不确定 → 接口先

组合 vs 继承

继承很容易过度使用:

// ❌ "拼装继承"
public class FlyingDog extends Dog { ... }
public class SwimmingDog extends Dog { ... }
// SwimmingFlyingDog?

// ✅ 组合 + 接口
public interface CanFly { void fly(); }
public interface CanSwim { void swim(); }

public class Duck extends Animal implements CanFly, CanSwim { ... }

优先组合 + 接口——继承用在"is-a"非常明确的关系(Cat is Animal),不要用来"借用功能"。

sealed class(Java 17+)

public sealed class Shape permits Circle, Square, Triangle {}

public final class Circle extends Shape { ... }
public final class Square extends Shape { ... }
public final class Triangle extends Shape { ... }

// ❌ public class Hexagon extends Shape { ... }   // 不在 permits 列表

sealed = "限定只能被 permits 列表里的类继承"。

好处:

  • 编译器知道所有子类 → switch 可以穷举性检查
  • 配 pattern matching 用——代数数据类型的 Java 表达

详见 第 12 篇

多态调用 + 实际类型

public class Animal {
    public void speak() { System.out.println("..."); }
}
public class Cat extends Animal {
    @Override
    public void speak() { System.out.println("meow"); }
}

List<Animal> animals = List.of(new Cat(), new Animal());
for (var a : animals) {
    a.speak();      // meow / ...
}

声明 Animal、实际 Cat → 调 Cat 的实现。

实战建议

  • 每个非 final class 思考"该不该 final"——大多数应该 final
  • 共享字段用 protected;私有的留 private
  • public API 谨慎用继承——别人继承了你以后改不动
  • 优先 组合 + 接口

→ 下一篇 接口