JDK 17 引入了密封类(Sealed Classes)的特性,它是 Java 15 中引入的密封类型(Sealed Types)的一部分,并在 JDK 17 中得到进一步的完善和改进。密封类和密封接口(Sealed Interfaces)提供了一种方式,用于限制哪些类或接口可以继承或实现它们。
密封类的概念
密封类是指一种限制其子类继承的类。通过声明一个类为密封类,开发者可以显式控制哪些类是该类的合法子类,而不允许其他任何类来继承它。这个特性为 Java 提供了更强的类型安全和可维护性。
如何声明密封类
密封类使用 sealed
关键字进行声明,并通过 permits
关键字列出允许继承它的子类。示例:
public sealed class Shape permits Circle, Rectangle {
// Shape 类是密封类,只允许 Circle 和 Rectangle 类继承它
}
public final class Circle extends Shape {
// Circle 是 Shape 类的一个合法子类
}
public final class Rectangle extends Shape {
// Rectangle 是 Shape 类的另一个合法子类
}
public class Triangle extends Shape {
// 编译错误:Triangle 无法继承 Shape,因为它不是被允许的子类
}
密封类的好处
- 类型安全: 通过限制继承,密封类提供了更加严格的类型控制,避免了外部代码(或库)对类的扩展。这意味着开发者可以准确地知道所有的子类,并进行精确的类型检查,从而减少了潜在的错误。
- 更好的模式匹配: 密封类与 Java 17 引入的模式匹配(Pattern Matching)相结合时,能够使模式匹配更高效。例如,在
switch
语句中使用密封类时,编译器可以确保覆盖所有合法子类,从而提高代码的可靠性和清晰性。 - 代码可维护性: 密封类帮助开发者控制继承结构,使得继承关系更具可预测性和可控性。在大型系统中,随着继承体系的扩展,控制哪些类可以继承某个类能有效减少意外继承带来的问题。
- 性能优化: 密封类在编译时就能确定其继承层级,从而可以为 JVM 进行优化。这有助于提升性能,尤其是在涉及模式匹配和虚拟方法调用的场景中。
密封类的限制
- 子类数量有限: 密封类只能允许指定的一组类继承,因此比普通类有更多的限制。这使得它不适合所有的继承场景。
- 不能无限制地继承: 密封类不允许其他类无条件地继承或实现,因此其继承树是有限的,这与普通类完全开放继承的方式不同。
例子:用密封类实现一个“形状”层次结构
假设我们需要设计一个形状系统,只有圆形、矩形和三角形是合法的形状。可以通过密封类来实现:
public sealed class Shape permits Circle, Rectangle, Triangle {
public abstract double area();
}
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public final class Rectangle extends Shape {
private final double length;
private final double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public double area() {
return length * width;
}
}
public final class Triangle extends Shape {
private final double base;
private final double height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
}
使用示例:
public class ShapeTest {
public static void main(String[] args) {
Shape circle = new Circle(5.0);
Shape rectangle = new Rectangle(4.0, 6.0);
Shape triangle = new Triangle(3.0, 7.0);
System.out.println("Circle area: " + circle.area());
System.out.println("Rectangle area: " + rectangle.area());
System.out.println("Triangle area: " + triangle.area());
}
}
在这个例子中,Shape
是一个密封类,它只允许 Circle
、Rectangle
和 Triangle
作为其子类。每个子类都重写了 area()
方法,计算各自形状的面积。
总结
密封类是 Java 17 引入的重要特性之一,它为开发者提供了更加严格的类型控制、增强了代码的可维护性和类型安全性,并且可以与模式匹配等其他新特性一起使用,提升了编程的效率和可靠性。