Java17中封类的是什么?
What are sealed classes in Java 17?
今天,我将我的Java版本从16更新到17,我发现sealed
类是其中的一个新特性。我认为可以这样声明:
public sealed class Main permits AClass, AnotherClass {
}
但是,Java中密封的类有什么用呢?
I also knew that it was a preview feature in jdk-15.
You can follow this link for examples.
简而言之,sealed 类 让您可以控制哪些模型,类 等可以实现或扩展 class/interface。
来自 link 的示例:
public sealed interface Service permits Car, Truck {
int getMaxServiceIntervalInMonths();
default int getMaxDistanceBetweenServicesInKilometers() {
return 100000;
}
}
该接口只允许 Car 和 Truck 实现它。
JEP 409解释为
A sealed class or interface can be extended or implemented only by
those classes and interfaces permitted to do so.
更实用的解释如下:
过去的情况是:
- 您无法限制一个接口被另一个接口扩展
- 您无法限制哪些 class 能够实现特定接口。
- 您必须将 class 声明为 final,以免被另一个 class 扩展。这样 class 就无法扩展已声明的 final class。这是非黑即白的方法。
目前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
您现在可以创建一个接口并且 select 仅允许特定的 class
实现该接口。不允许所有其他 class 实施它。
示例:
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
您现在可以限制 class 被扩展(与之前的 final 相同)但您现在可以允许某些特定的 class 扩展它。所以现在你有更多的控制权,因为关键字 final 是绝对限制每个 class 扩展声明的 final class
示例:
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
重要提示:
密封的 class 及其允许的子 class 必须属于同一模块,并且如果在未命名模块中声明,则属于同一包。
示例:
假设我们有相同的未命名模块和以下包
-packageA
-Implementationclass1.java
-packageB
-MotherClass.java
或
-root
-MotherClass.java
-packageA
-Implementationclass1.java
您将收到错误 Class is not allowed to extend sealed class from another package。因此,如果您有一个未命名的模块,所有参与的 class 密封功能的 es 和接口必须完全放在同一个包中。
每个允许的子class必须直接扩展密封的class。
密封类
- 密封 class 是一个 class 或接口,它限制其他 class 实体或接口可以扩展它。
- 密封 classes 和接口表示受限的 class 层次结构,提供对继承的更多控制。
- 密封class的所有直接子class在编译时都是已知的。 class sealed class 模块编译后不能出现其他子class。
- 例如, 第三方客户端无法在他们的代码中扩展您的密封 class。因此,密封的 class 的每个实例都有一个来自
编译此 class 时已知的有限集合。
定义密封 类
要密封 class,请将密封修饰符添加到其声明中。然后,在任何 extends 和 implements 子句之后,添加 permits 子句。此子句指定可以扩展密封 class.
的 classes
例如,Shape 的以下声明指定了三种允许的子class,Circle、Square 和Rectangle:
public sealed class Shape
permits Circle, Square, Rectangle {
}
定义以下三个允许的subclasses,Circle,Square,和Rectangle,在与sealed class相同的模块或相同的包中:
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;
}
Rectangle 还有一个子class, FilledRectangle:
public final class FilledRectangle extends Rectangle {
public int red, green, blue;
}
对允许子项的限制classes
它们必须在编译时被密封 class 访问。
比如要编译Shape.java
,编译器必须能够
访问所有允许的 classes 形状:Circle.java
,
Square.java
,以及 Rectangle.java
。此外,由于 Rectangle 是
sealed class,编译器还需要访问 FilledRectangle.java
.
他们必须直接扩展密封的class。
他们必须恰好具有以下修饰符之一来描述如何
它继续由其 superclass:
发起的密封
- 最终:无法进一步扩展
- sealed: 只能通过其允许的 subclasses
进行扩展
- 非密封:可以通过未知子classes扩展;密封的 class
无法阻止其允许的子classes 这样做
例如,允许的 Shape 子class 展示了每个
这三个修饰符:Circle
是最终的,而 Rectangle
是密封的,
Square
未密封。
它们必须与密封的class在同一个模块中(如果密封
class 在命名模块中)或在同一个包中(如果密封
class 位于未命名模块中,如 Shape.java 示例中所示)。
例如com.example.graphics.Shape
下面声明的,它的permitted subclasses
都在不同的包中。此示例仅在 Shape
及其所有允许的子 class 都在同名模块中时才能编译。
package com.example.graphics;
public sealed class Shape
permits com.example.polar.Circle,
com.example.quad.Rectangle,
com.example.quad.simple.Square { }
根据此 documentation,密封 classes 和接口限制哪些其他 classes 或接口可以扩展或实现它们。它更像是一种限制使用 superclass 而不是使用访问修饰符的声明方式。
在 Java 中,class 可以是最终的,因此没有其他 classes 可以子class 它。如果 class 不是最终的,那么它对所有其他 class 开放以支持代码可重用性。这样做会引起数据建模问题。
下面的 NumberSystem class 对所有 class 开放,因此任何子class 都可以扩展它。如果您想将此 NumberSystem 限制为一组固定的子classes(二进制、十进制、八进制和十六进制)怎么办?。这意味着您不希望任何其他任意 class 扩展此 NumberSystem class.
class NumberSystem { ... }
final class Binary extends NumberSystem { ... }
final class Decimal extends NumberSystem { ... }
final class Octal extends NumberSystem { ... }
final class HexaDecimal extends NumberSystem { ... }
使用密封 class,您可以通过控制可以扩展它的子class 来实现它,并防止任何其他任意 class 这样做。
所有sealed
java classes或接口必须使用permits
关键字。例如:
Parent.class:
public sealed class Parent permits Child1, Child2 {
void parentMethod() {
System.out.println("from a sealed parent class ");
}
}
Child1.java:
public final class Child1 extends Parent {
public static void main(String[] args) {
Child1 obj = new Child1();
obj.parentMethod();
}
}
Child2.java:
public final class Child2 extends Parent {
public static void main(String[] args) {
Child2 obj = new Child2();
obj.parentMethod();
}
}
Child3.java
public final class Child3 extends Parent {
public static void main(String[] args) {
Child3 obj = new Child3();
obj.parentMethod();
}
}
这个 Child3
class 代码会抛出一个编译时错误说
扩展密封 class Parent 的类型 Child3 应该是 Parent (permits Child3
, 就像 Child1
和 Child2
) 允许的子类型。
今天,我将我的Java版本从16更新到17,我发现sealed
类是其中的一个新特性。我认为可以这样声明:
public sealed class Main permits AClass, AnotherClass {
}
但是,Java中密封的类有什么用呢?
I also knew that it was a preview feature in jdk-15.
You can follow this link for examples.
简而言之,sealed 类 让您可以控制哪些模型,类 等可以实现或扩展 class/interface。
来自 link 的示例:
public sealed interface Service permits Car, Truck {
int getMaxServiceIntervalInMonths();
default int getMaxDistanceBetweenServicesInKilometers() {
return 100000;
}
}
该接口只允许 Car 和 Truck 实现它。
JEP 409解释为
A sealed class or interface can be extended or implemented only by those classes and interfaces permitted to do so.
更实用的解释如下:
过去的情况是:
- 您无法限制一个接口被另一个接口扩展
- 您无法限制哪些 class 能够实现特定接口。
- 您必须将 class 声明为 final,以免被另一个 class 扩展。这样 class 就无法扩展已声明的 final class。这是非黑即白的方法。
目前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
您现在可以创建一个接口并且 select 仅允许特定的 class 实现该接口。不允许所有其他 class 实施它。
示例:
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
您现在可以限制 class 被扩展(与之前的 final 相同)但您现在可以允许某些特定的 class 扩展它。所以现在你有更多的控制权,因为关键字 final 是绝对限制每个 class 扩展声明的 final class
示例:
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
重要提示:
密封的 class 及其允许的子 class 必须属于同一模块,并且如果在未命名模块中声明,则属于同一包。
示例:
假设我们有相同的未命名模块和以下包
-packageA -Implementationclass1.java -packageB -MotherClass.java
或
-root -MotherClass.java -packageA -Implementationclass1.java
您将收到错误 Class is not allowed to extend sealed class from another package。因此,如果您有一个未命名的模块,所有参与的 class 密封功能的 es 和接口必须完全放在同一个包中。
每个允许的子class必须直接扩展密封的class。
密封类
- 密封 class 是一个 class 或接口,它限制其他 class 实体或接口可以扩展它。
- 密封 classes 和接口表示受限的 class 层次结构,提供对继承的更多控制。
- 密封class的所有直接子class在编译时都是已知的。 class sealed class 模块编译后不能出现其他子class。
- 例如, 第三方客户端无法在他们的代码中扩展您的密封 class。因此,密封的 class 的每个实例都有一个来自 编译此 class 时已知的有限集合。
定义密封 类
要密封 class,请将密封修饰符添加到其声明中。然后,在任何 extends 和 implements 子句之后,添加 permits 子句。此子句指定可以扩展密封 class.
的 classes例如,Shape 的以下声明指定了三种允许的子class,Circle、Square 和Rectangle:
public sealed class Shape
permits Circle, Square, Rectangle {
}
定义以下三个允许的subclasses,Circle,Square,和Rectangle,在与sealed class相同的模块或相同的包中:
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;
}
Rectangle 还有一个子class, FilledRectangle:
public final class FilledRectangle extends Rectangle {
public int red, green, blue;
}
对允许子项的限制classes
它们必须在编译时被密封 class 访问。
比如要编译
Shape.java
,编译器必须能够 访问所有允许的 classes 形状:Circle.java
,Square.java
,以及Rectangle.java
。此外,由于 Rectangle 是 sealed class,编译器还需要访问FilledRectangle.java
.他们必须直接扩展密封的class。
他们必须恰好具有以下修饰符之一来描述如何 它继续由其 superclass:
发起的密封- 最终:无法进一步扩展
- sealed: 只能通过其允许的 subclasses 进行扩展
- 非密封:可以通过未知子classes扩展;密封的 class 无法阻止其允许的子classes 这样做
例如,允许的 Shape 子class 展示了每个 这三个修饰符:
Circle
是最终的,而Rectangle
是密封的,Square
未密封。它们必须与密封的class在同一个模块中(如果密封 class 在命名模块中)或在同一个包中(如果密封 class 位于未命名模块中,如 Shape.java 示例中所示)。
例如com.example.graphics.Shape
下面声明的,它的permitted subclasses
都在不同的包中。此示例仅在 Shape
及其所有允许的子 class 都在同名模块中时才能编译。
package com.example.graphics;
public sealed class Shape
permits com.example.polar.Circle,
com.example.quad.Rectangle,
com.example.quad.simple.Square { }
根据此 documentation,密封 classes 和接口限制哪些其他 classes 或接口可以扩展或实现它们。它更像是一种限制使用 superclass 而不是使用访问修饰符的声明方式。
在 Java 中,class 可以是最终的,因此没有其他 classes 可以子class 它。如果 class 不是最终的,那么它对所有其他 class 开放以支持代码可重用性。这样做会引起数据建模问题。
下面的 NumberSystem class 对所有 class 开放,因此任何子class 都可以扩展它。如果您想将此 NumberSystem 限制为一组固定的子classes(二进制、十进制、八进制和十六进制)怎么办?。这意味着您不希望任何其他任意 class 扩展此 NumberSystem class.
class NumberSystem { ... }
final class Binary extends NumberSystem { ... }
final class Decimal extends NumberSystem { ... }
final class Octal extends NumberSystem { ... }
final class HexaDecimal extends NumberSystem { ... }
使用密封 class,您可以通过控制可以扩展它的子class 来实现它,并防止任何其他任意 class 这样做。
所有sealed
java classes或接口必须使用permits
关键字。例如:
Parent.class:
public sealed class Parent permits Child1, Child2 {
void parentMethod() {
System.out.println("from a sealed parent class ");
}
}
Child1.java:
public final class Child1 extends Parent {
public static void main(String[] args) {
Child1 obj = new Child1();
obj.parentMethod();
}
}
Child2.java:
public final class Child2 extends Parent {
public static void main(String[] args) {
Child2 obj = new Child2();
obj.parentMethod();
}
}
Child3.java
public final class Child3 extends Parent {
public static void main(String[] args) {
Child3 obj = new Child3();
obj.parentMethod();
}
}
这个 Child3
class 代码会抛出一个编译时错误说
扩展密封 class Parent 的类型 Child3 应该是 Parent (permits Child3
, 就像 Child1
和 Child2
) 允许的子类型。