单继承
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:禁止继承(例:String、Integer)。
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 谨慎用继承——别人继承了你以后改不动
- 优先 组合 + 接口
→ 下一篇 接口