60 java class sealed-class java-sealed-type java-17
今天,我将Java版本从16更新到17,我发现sealed类是其中的一个新功能。我认为可以这样声明:
public sealed class Main permits AClass, AnotherClass {
}
Run Code Online (Sandbox Code Playgroud)
但是,Java 中的密封类有什么用呢?
我还知道这是JDK 15中的预览功能。
JDT*_*One 47
简而言之,密封类使您可以控制哪些模型、类等可以实现或扩展该类/接口。
链接中的示例:
public sealed interface Service permits Car, Truck {
int getMaxServiceIntervalInMonths();
default int getMaxDistanceBetweenServicesInKilometers() {
return 100000;
}
}
Run Code Online (Sandbox Code Playgroud)
该接口只允许Car和Truck实现。
Pan*_*kos 33
JEP 409将其解释为
密封类或接口只能由那些允许这样做的类和接口进行扩展或实现。
更实际的解释如下:
过去的情况是:
目前sealed关键字的情况是:
现在,您可以限制其他接口扩展某个接口,并仅针对某些允许扩展该接口的特定接口制定规则。
例子:
public sealed interface MotherInterface permits ChildInterfacePermitted {}
//Has to be declared either as sealed or non-sealed
public non-sealed interface ChildInterfacePermitted extends MotherInterface {}
public interface AnotherChildInterface extends MotherInterface {}
//compiler error! It is not included in the permits of mother inteface
Run Code Online (Sandbox Code Playgroud)
您现在可以创建一个接口并仅选择允许实现该接口的特定类。所有其他类都不允许实现它。
例子:
public sealed interface MotherInterface permits ImplementationClass1 {}
//Has to be declared either as final or as sealed or as non-sealed
public final class ImplementationClass1 implements MotherInterface {}
public class ImplementationClass2 implements MotherInterface {}
//compiler error! It is not included in the permits of mother inteface
Run Code Online (Sandbox Code Playgroud)
您现在可以限制要扩展的类(与之前的 Final 相同),但现在可以允许某些特定的类对其进行扩展。所以现在你有了更多的控制权,就像以前一样,关键字final绝对限制每个类扩展声明的final类
例子:
public sealed class MotherClass permits ChildClass1 {}
//Has to be declared either as final or as sealed or as non-sealed
public non-sealed class ChildClass1 extends MotherClass {}
public class ChildClass2 extends MotherClass {}
//compiler error! It is not included in the permits of MotherClass
Run Code Online (Sandbox Code Playgroud)
密封类及其允许的子类必须属于同一模块,并且如果在未命名模块中声明,则必须属于同一包。
例子:
假设我们有相同的未命名模块和以下包
-packageA
-Implementationclass1.java
-packageB
-MotherClass.java
Run Code Online (Sandbox Code Playgroud)
或者
-root
-MotherClass.java
-packageA
-Implementationclass1.java
Run Code Online (Sandbox Code Playgroud)
您将收到错误Class is not allowed toextend sealed class from another package。因此,如果您有一个未命名的模块,则密封函数的所有参与类和接口都必须完全相同地放置在同一个包中。
每个允许的子类必须直接扩展密封类。
密封课程
密封类是一种约束,只允许给定的类实现它。sealed这些允许的类必须显式扩展密封类,并且还具有、non-sealed或修饰符之一 final。该功能从 java 17 ( JEP 409 ) 开始提供,并且在更早之前 (Java 15) 就已作为预览版提供。
sealed interface IdentificationDocument permits IdCard, Passport, DrivingLicence { }
Run Code Online (Sandbox Code Playgroud)
final class IdCard implements IdentificationDocument { }
final class Passport implements IdentificationDocument { }
non-sealed class DrivingLicence implements IdentificationDocument { }
class InternationalDrivingPermit extends DrivingLicence {}
Run Code Online (Sandbox Code Playgroud)
与模式匹配一起使用
我发现这个新功能与 Java 17 ( JEP 406 )中作为预览引入的模式匹配结合起来非常棒!
允许的类限制确保所有子类在编译时都是已知的。使用switch表达式( Java 14 中的JEP 361),编译器需要列出所有允许的类或default对其余类使用关键字。考虑使用上面的类的以下示例:
final String code = switch(identificationDocument) {
case IdCard idCard -> "I";
case Passport passport -> "P";
};
Run Code Online (Sandbox Code Playgroud)
编译器会产生javac Application.java --enable-preview -source 17错误:
Run Code Online (Sandbox Code Playgroud)Application.java:9: error: the switch expression does not cover all possible input values final String code = switch(identificationDocument) { ^ Note: Application.java uses preview features of Java SE 17. Note: Recompile with -Xlint:preview for details. 1 error
一旦使用了所有允许的类或default关键字,编译就会成功:
final String code = switch(identificationDocument) {
case IdCard idCard -> "I";
case Passport passport -> "P";
case DrivingLicence drivingLicence -> "D";
};
Run Code Online (Sandbox Code Playgroud)
密封类是 Java 语言的补充,为类作者提供了对哪些类可以扩展它的细粒度控制。以前,您可以允许每个人继承您的类,也可以完全禁止它(使用“final”)。它也适用于接口。
此外,它是模式匹配功能的先决条件,因为所有后代在编译期间都是已知的。
像往常一样,有一个缺点 - 密封类和接口不能被模拟/伪造,这是测试障碍。