当前位置: 首页 > 知识库问答 >
问题:

Java 17中的密封类是什么?

巫煌
2023-03-14

今天,我将Java版本从16更新到17,我发现密封类是其中的一个新特性。我认为可以这样宣布:

public sealed class Main permits AClass, AnotherClass {
}

但是,Java中密封类的用途是什么?

我还知道这是jdk-15中的预览功能。

共有3个答案

终洛华
2023-03-14

密封类

  • 密封类是一个类或接口,它限制哪些其他类或接口可以扩展它
  • 密封的类和接口表示受限的类层次结构,它们提供了对html" target="_blank">继承的更多控制
  • 一个密封类的所有直接子类在编译时都是已知的。编译带有密封类的模块后,可能不会出现其他子类
  • 例如,第三方客户端无法在其代码中扩展密封类。因此,密封类的每个实例都有一个有限集合中的类型,该集合在编译该类时是已知的

定义密封类

要密封类,请将密封修饰符添加到其声明中。然后,在任何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类。

    它们必须具有以下修改器中的一个,以描述其如何继续由其超类启动的密封:

    1. 最终:无法进一步扩展
    2. 密封:只能由其允许的子类扩展
    3. 非密封:可以由未知的子类扩展;密封类不能阻止其允许的子类这样做

    例如,允许的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 { }
    

  • 洪成济
    2023-03-14

    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类。

  • 万修然
    2023-03-14

    您可以点击此链接获取示例。

    简而言之,密封类可以控制哪些模型、类等可以实现或扩展该类/接口。

    链接示例:

    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 编译并运行程序 输出结果为