Java 17中的密封类(Sealed Classes)是一个重要的新特性,它提供了一种机制来限制哪些类可以继承一个给定的类或者实现一个给定的接口。这个特性通过sealed和permits关键字来实现,旨在增强类型安全性,简化代码结构,并在编译时进行更精确的检查。

密封类可以让我们更好的控制哪些类可以对我定义的类进行扩展。密封类可能对于框架或中间件的开发者更有用。在这之前一个类要么是可以被extends的,要么是final的,只有这两种选项。

密封类可以控制有哪些类可以对超类进行继承,在Java 17之前如果我们需要控制哪些类可以继承,可以通过改变类的访问级别,比如去掉类的public,访问级别为默认。

密封类的基本概念

定义:密封类是通过sealed修饰符声明的类,它限制了哪些类可以继承它。同时,使用permits关键字来指定哪些子类是被允许的。

目的:防止类的无序扩展,确保类的继承体系在可控范围内,减少潜在的错误和异常逻辑。

密封类的语法

public sealed class 父类名 permits 子类1, 子类2, ... {  
    // 类成员  
}  
  
public final class 子类1 extends 父类名 {  
    // 子类1成员  
}  
  
public sealed class 子类2 extends 父类名 permits 子类2_1, ... {  
    // 子类2成员  
}  

// 或者  
public non-sealed class 子类3 extends 父类名 {  
    // 子类3成员,子类3可以被任意类继承  
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

密封类的特点

  • 继承限制:只有被permits子句明确允许的类才能继承密封类。
  • 灵活性:子类可以继续被声明为sealed(限制继承)、final(禁止继承)或non-sealed(恢复开放继承)。
  • 编译时检查:密封类提供了编译时的类型检查,确保不会出现意外的继承关系。
  • 不支持匿名类和函数式接口:由于密封类需要明确的继承关系,因此不支持匿名类和函数式接口的继承。

密封类的使用场景

框架和库设计:在框架和库的设计中,使用密封类可以更好地控制类的继承体系,减少代码耦合性,提高代码的可读性和可维护性。
类型安全:通过限制类的继承,可以减少类型转换的错误和潜在的运行时异常,提高程序的稳定性。
代码简化:密封类可以减少需要显式声明的类和接口数量,简化代码结构。

示例

public sealed interface Shape permits Circle, Rectangle, Square {  
    double area();  
}  
  
public final class Circle implements Shape {  
    private final double radius;  
    // ...  
}  
  
public sealed class Rectangle implements Shape permits Square {  
    // Rectangle特有成员  
    // ...  
}  
  
public final class Square extends Rectangle {  
    // Square特有成员  
    // ...  
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

在这个例子中,Shape是一个密封接口,它只允许Circle、Rectangle和Square这三个类实现。同时,Rectangle也被声明为密封类,它只允许Square作为其子类。这样的设计使得类的继承体系更加清晰和可控。

Java 17中的密封类是一个重要的语言特性,它提供了对类继承关系的更细粒度控制。通过限制哪些类可以继承一个给定的类或者实现一个给定的接口,密封类增强了类型安全性,简化了代码结构,并在编译时进行了更精确的检查。这对于框架和库的设计者来说尤其有用,因为它可以更好地控制类的继承体系,减少代码耦合性,提高代码的可读性和可维护性。