25

今天我将我的 java 版本从 16 更新到 17,我发现sealedclass 是其中的一个新特性。我认为可以这样声明——

public sealed class Main{

}

但是java中密封类有什么用呢?

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

4

5 回答 5

20

您可以按照此链接获取示例。

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

链接中的示例:

public sealed interface Service permits Car, Truck {

    int getMaxServiceIntervalInMonths();

    default int getMaxDistanceBetweenServicesInKilometers() {
    return 100000;
  }
}

这个接口只允许 Car 和 Truck 实现它。

于 2021-09-17T06:29:47.880 回答
10

JEP 409将其解释为

密封的类或接口只能由允许这样做的类和接口扩展或实现。

更实际的解释如下:

过去的情况是:

  • 您不能限制由另一个接口扩展的接口
  • 您无法限制哪些类能够实现特定接口。
  • 您必须将一个类声明为 final,以免被另一个类扩展。这样,任何类都不能扩展声明的最终类。这是非黑即白的方法。

使用密封关键字的当前情况是:

  • 您现在可以限制由其他接口扩展的接口,并为仅允许扩展它的某些特定接口制定规则。

    例子:

    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
    

    你会得到错误Class is not allowed to extend seal class from another package。因此,如果您有一个未命名的模块,则密封函数的所有参与类和接口必须完全放在同一个包中。

  • 每个允许的子类都必须直接扩展密封类。

于 2021-09-18T11:41:33.843 回答
0

密封类

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

定义密封类

要密封类,请将密封修饰符添加到其声明中。然后,在任何 extends 和 implements 子句之后,添加 permit 子句。本条款规定了可以扩展密封类的类。

例如,以下 Shape 声明指定了三个允许的子类,Circle、Square 和 Rectangle:

public sealed class Shape
    permits Circle, Square, Rectangle {
}

在与密封类相同的模块或相同的包中定义以下三个允许的子类 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;
}

Rectangle 有另一个子类 FilledRectangle:

public final class FilledRectangle extends Rectangle {
    public int red, green, blue;
}

允许的子类的约束

  • 它们必须在编译时可由密封类访问。

    例如,要编译Shape.java,编译器必须能够访问所有允许的 Shape 类:Circle.javaSquare.javaRectangle.java。此外,由于 Rectangle 是一个密封类,编译器还需要访问FilledRectangle.java.

  • 他们必须直接扩展密封类。

  • 它们必须恰好具有以下修饰符之一来描述它如何继续由其超类发起的密封:

    1. final : 不能进一步扩展
    2. 密封:只能由其允许的子类扩展
    3. non-sealed:可以被未知的子类扩展;密封类不能阻止其允许的子类这样做
  • 例如,允许的 Shape 子类演示了这三个修饰符中的每一个:Circleis final whileRectangle是 seal 和 TheSquare是 non-sealed。

  • 它们必须与密封类在同一个模块中(如果密封类在命名模块中)或在同一个包中(如果密封类在未命名模块中,如 Shape.java 示例中)。

例如,在下面的声明中com.example.graphics.Shape,它permitted subclasses都在不同的包中。Shape只有当所有允许的子类都在同名模块中时,此示例才会编译。

package com.example.graphics;

    public sealed class Shape 
        permits com.example.polar.Circle,
                com.example.quad.Rectangle,
                com.example.quad.simple.Square { }
于 2021-09-27T04:17:27.973 回答
0

所有sealedjava 类或接口都必须使用permits关键字。例如:

父类:

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代码将引发编译时错误,指出扩展密封类 Parent 的类型 Child3 应该是 Parent ( permits Child3,就像Child1and Child2) 的允许子类型。

于 2022-01-18T15:48:08.717 回答
0

根据本文档,密封类和接口限制了哪些其他类或接口可以扩展或实现它们。它更像是一种声明性方式来限制超类的使用,而不是使用访问修饰符。

在 Java 中,一个类可以是 final 的,所以没有其他类可以继承它。如果一个类不是最终的,那么它对所有其他类开放以支持代码可重用性。这样做会引发数据建模问题。

下面的 NumberSystem 类对所有类开放,因此任何子类都可以扩展它。如果您想将此 NumberSystem 限制为一组固定的子类(Binary、Decimal、Octal 和 HexaDecimal)怎么办?这意味着您不希望任何其他任意类扩展此 NumberSystem 类。

class NumberSystem { ... }
final class Binary extends NumberSystem { ... }
final class Decimal extends NumberSystem { ... }
final class Octal extends NumberSystem { ... }
final class HexaDecimal extends NumberSystem { ... }

使用密封类,您可以通过控制可以扩展它的子类来实现它,并防止任何其他任意类这样做。

于 2021-11-06T02:38:08.287 回答