声明密封类型
限制哪些类型可以扩展该类型
声明密封类型 是 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 反馈 — 无需本地设置。