0Pricing
Java Academy · 课时

声明密封类型

限制哪些类型可以扩展该类型

声明密封类型 是 CoddyKit 上的免费 Java Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

什么是密封类型

密封类或接口会限制哪些其他类型可以继承或实现它。这样,您就可以对一组封闭的可能性进行建模,让编译器能够对其进行推理。

它解决的问题

普通的 public 类可以被任何人在任何地方继承。有时,您希望只有三个图形或两种支付类型,不允许出现意外情况。密封机制会明确表达这一意图,并强制执行它。

密封关键字

将类型标记为 sealed,并使用 permits 列出允许的子类型。每个被允许的子类型都必须声明自己的继承修饰符。

public class Main {
    sealed interface Shape permits Circle, Square {}
    record Circle(double radius) implements Shape {}
    record Square(double side) implements Shape {}

    public static void main(String[] args) {
        Shape s = new Circle(2.0);
        System.out.println(s);
    }
}

子类型修饰符

每个被允许的子类型都必须是以下类型之一:final(不允许继续创建子类)、sealed(继续施加限制)或 non-sealed(重新开放,允许自由扩展)。记录类隐式具有 final 修饰。

final 子类

将子类标记为 final,就会在该分支处终止继承层次。

public class Main {
    sealed interface Animal permits Dog, Cat {}
    static final class Dog implements Animal {
        public String toString() { return "Dog"; }
    }
    static final class Cat implements Animal {
        public String toString() { return "Cat"; }
    }

    public static void main(String[] args) {
        Animal a = new Dog();
        System.out.println(a);
    }
}

非密封子类

non-sealed 子类型会有意重新开放扩展,从而允许未知类再次继承它。当某个分支必须保持开放时,请谨慎使用它。

public class Main {
    sealed interface Plugin permits CorePlugin, ExternalPlugin {}
    static final class CorePlugin implements Plugin {}
    static non-sealed class ExternalPlugin implements Plugin {}
    static class ThirdParty extends ExternalPlugin {}

    public static void main(String[] args) {
        Plugin p = new ThirdParty();
        System.out.println(p.getClass().getSimpleName());
    }
}

密封类同样适用

密封机制并不局限于接口。抽象的 sealed class 也以相同方式工作,并且可以保存共享状态和行为。

public class Main {
    sealed static abstract class Expr permits Num, Add {}
    static final class Num extends Expr {
        final int value;
        Num(int value) { this.value = value; }
    }
    static final class Add extends Expr {
        final Expr left, right;
        Add(Expr left, Expr right) { this.left = left; this.right = right; }
    }

    public static void main(String[] args) {
        Expr e = new Add(new Num(1), new Num(2));
        System.out.println(e.getClass().getSimpleName());
    }
}

同一模块或包

被允许的子类型必须与密封类型位于同一模块中;如果代码不是模块化代码,则必须位于同一个包中。这样可以将这个封闭集合集中在一起,并确保它可以得到验证。

编译器强制执行

如果某个类尝试继承密封类型,却没有在 permits 中列出,代码将无法编译。这个封闭集合会在编译时得到保证。

为什么这很重要

由于编译器知道每个子类型,因此可以验证针对密封类型的 switch 是否处理了所有情况。这是穷举式模式匹配的基础,我们将在后续课程中介绍它。

完整的继承层次

下面是一个用作值模型的小型封闭继承层次。

public class Main {
    sealed interface Json permits JsonNull, JsonNumber, JsonString {}
    record JsonNull() implements Json {}
    record JsonNumber(double value) implements Json {}
    record JsonString(String value) implements Json {}

    public static void main(String[] args) {
        Json[] values = { new JsonNull(), new JsonNumber(3.5), new JsonString("hi") };
        for (Json j : values) {
            System.out.println(j);
        }
    }
}

快速检查

请检验您对密封声明的理解。

回顾

您学会了声明密封类型。

  • sealed 会限制哪些类型可以继承或实现某个类型。
  • permits 子句会列出允许的子类型。
  • 每个子类型都必须是 final、sealed 或 non-sealed。
  • 子类型必须位于同一模块或包中,并由编译器强制执行这些限制。

常见问题解答

「声明密封类型」课时是免费的吗?

是的 — 「声明密封类型」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「声明密封类型」这节课中我会学到什么?

限制哪些类型可以扩展该类型 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「声明密封类型」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 声明密封类型
  2. permits 子句
  3. 使用 Record 实现密封类型
  4. 对密封类型使用穷尽式 switch
← 返回 Java Academy