今天,我将Java版本从16更新到17,我发现密封类是其中的一个新特性。我认为可以这样宣布:
public sealed class Main permits AClass, AnotherClass {
}
但是,Java中密封类的用途是什么?
我还知道这是jdk-15中的预览功能。
密封类
定义密封类
要密封类,请将密封修饰符添加到其声明中。然后,在任何extends和implements子句之后,添加permits子句。本条款规定了可扩展密封类的类。
例如,以下形状声明指定了三个允许的子类:圆形、方形和矩形:
public sealed class Shape
permits Circle, Square, Rectangle {
}
在与sealed类相同的模块或包中定义以下三个允许的子类:Circle、Square和Rectangle:
public final class Circle extends Shape {
public float radius;
}
public non-sealed class Square extends Shape {
public double side;
}
public sealed class Rectangle extends Shape permits FilledRectangle {
public double length, width;
}
矩形还有一个子类,FilledRectgle:
public final class FilledRectangle extends Rectangle {
public int red, green, blue;
}
对允许子类的约束
>
它们必须在编译时被密封类访问。
例如,编译形状。在java中,编译器必须能够访问所有允许的形状类:Circle。java,方形。java和矩形。java
。此外,由于Rectangle是一个密封类,编译器还需要访问FilledRectangle。java。
它们必须直接扩展sealed类。
它们必须具有以下修改器中的一个,以描述其如何继续由其超类启动的密封:
例如,允许的Shape子类演示了这三个修饰符中的每一个:Circle
是最终修饰符,而Rectangle
是密封的,而Square
是非密封的。
它们必须与密封类位于同一模块中(如果密封类位于命名模块中)或位于同一包中(如果密封类位于未命名模块中,如Shape.java示例中所示)。
例如,在下面的com.example.graphics.Shape
声明中,它的允许的子类
都在不同的包中。只有当Shape
及其所有允许的子类都在同名模块中时,此示例才会编译。
package com.example.graphics;
public sealed class Shape
permits com.example.polar.Circle,
com.example.quad.Rectangle,
com.example.quad.simple.Square { }
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
现在,您可以创建一个接口,并仅选择允许实现该接口的特定类。不允许所有其他类实现它。
例子:
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
现在可以限制要扩展的类(与之前使用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
>
例子:
假设我们有相同的未命名模块和以下包
-packageA
-Implementationclass1.java
-packageB
-MotherClass.java
或
-root
-MotherClass.java
-packageA
-Implementationclass1.java
您将得到错误类不允许从另一个包扩展密封类。因此,如果您有一个未命名的模块,那么密封函数的所有参与类和接口必须完全放在同一个包中。
每个允许的子类都必须直接扩展sealed类。
您可以点击此链接获取示例。
简而言之,密封类可以控制哪些模型、类等可以实现或扩展该类/接口。
链接示例:
public sealed interface Service permits Car, Truck {
int getMaxServiceIntervalInMonths();
default int getMaxDistanceBetweenServicesInKilometers() {
return 100000;
}
}
此接口仅允许Car and Truck实现它。
下面的代码在无法通过条件颜色时编译。深色和彩色。浅色,因为这两个类是抽象的。 我错过什么了吗?
如果我声明以下密封层次结构 没有使用模块(没有module-info.java),并尝试用Maven编译它 我知道https://openjdk.java.net/jeps/409和这个部分: 许可指定的类必须位于超类附近:在同一个模块中(如果超类在命名模块中)或在同一个包中(如果超类在未命名模块中)。 然而,Maven在编译时不应该默认使用类路径吗?这一限制是否可以避免? 如果没有,这是否开创了
主要内容:Java16 sealed密封类的示例Java 15 引入了一个密封类作为预览功能,它提供了对继承的细粒度控制。Java 16 提供了一些小的增强功能,并将此功能保留为预览版。以下是密封类需要考虑的要点 : 密封类是使用 sealed 关键字声明的。 密封类允许使用 permit 关键字声明哪个类可以是子类型。 扩展密封类的类必须声明为sealed 、non-sealed或final的。 密封类有助于在继承中创建有限且可确定的类层次结
主要内容:Java15 sealed 密封类的示例Java 15 引入了一个密封类作为预览功能,它提供了对继承的细粒度控制。以下是密封类需要考虑的要点 : 密封类是使用 sealed 关键字声明的。 密封类允许使用 permit 关键字声明哪个类可以是子类型。 继承密封类的类必须声明为sealed 、non-sealed或final的。 密封类有助于在继承中创建有限且可确定的类层次结构。 Java15 sealed 密封类的示例 ApiTeste
数据类可以扩展密封类,但不是,我不确定它们如何/是否能够接受“supertype”密封类所需的参数。 > 从密封类扩展常规类可以很好地编译。 但是,将其更改为数据类并不编译(“数据类主构造函数必须只具有属性(val/var)参数”)。 否则,我的选择似乎是使用选项1处理我自己的数据类功能(copy、hashcode、equals等),或者通过使用选项4打开超类型属性来进行折衷。
主要内容: Record的sealed密封类的示例由于默认情况下Record是final的,并且可以继承接口。我们可以定义密封接口并让Record实现它们以更好地管理代码。 Record的sealed密封类的示例 ApiTester.java 编译并运行程序 输出结果为