Java中密封类的介绍

2023-03-07 09:27:27 浏览数 (1)

大家好,我是小面。今天将给大家介绍一下Java中的密封类。

Sealed类是Java武器库中的一个新引入(JDK17)。由于这一添加,在Java编程语言中的关键字集合中添加了另一个关键字。事实上,引入了几个新的关键字来支持密封类:密封和非密封。

这些类扩充了继承的经典概念,在继承概念中,只有一组特定的子类才能扩展父类。因此,本质上,Final类不允许继承。同时,非final类可以由任何子类继承。Sealed类介于两者之间,只指定允许继承的一些类。本编程教程通过代码示例和用例介绍了Java中Sealed类的用法和概念。

什么是Java中的继承?

作为一个补充,继承是一种面向对象的特性,其中继承的类扩展了其父类的特性或功能。这增强了可重用性。子类继承父类的质量(字段、方法和嵌套类),并可以通过多态性和函数重载添加自己的质量。与其他支持多重继承的面向对象编程语言不同,Java严格支持单一继承。一个子类只能扩展一个父类(父类和子类之间的父子关系)。下面是Java中的继承示例:

代码语言:javascript复制
class Bird {
    String greet;
    Bird(){
        greet="?!";
    }
    void saySomething(){        
        System.out.println(greet);        
    }
}

class Duck extends Bird{
    Duck(){
        greet="Quack, Quack";
    }
    void saySomething(){
        System.out.println(greet);
    }
}

然而,请注意,当开发人员使用接口时,没有这种限制。Java允许类实现多个接口,如以下示例代码所示:

代码语言:javascript复制
class Bird {
    String greet;
    Bird(){
        greet="?!";
    }
    void saySomething(){        
        System.out.println(greet);        
    }
}

interface CanFly{
    default void shoo() {
        System.out.println("fly...");
    }
}

interface CannotFly{
    default void shoo() {
        System.out.println("run...");
    }
}

class Ostrich extends Bird implements CannotFly{
    Ostrich(){
        greet="boom";
    }
    void saySomething(){
        System.out.println(greet);
        shoo();
    }
}

什么是Java的final类?

如果程序员想要限制类的继承或使其绝对不可继承,我们可以简单地以最后一个关键字开始类定义。此关键字的目的是防止类被子类化。因此,类变得不可修改和不可扩展。下面是一些示例代码,演示如何在Java中使用final关键字:

代码语言:javascript复制
final class A {
    void func(){
        System.out.println("final class");
    }
}

class B extends A {} // 这里是不允许继承的

Java中的抽象类是什么?

如果开发人员希望确保在不扩展类的情况下无法创建任何对象,我们可以使用关键字abstract声明一个类。尽管抽象可以具有常规类的所有特性,但使用abstract关键字使其变得特别。为了创建这个类的对象,程序员需要用一个非抽象类来扩展它,只有这样我们才能创建它的实例。从这个意义上讲,接口实际上像Java中的纯抽象类。下面是一个示例:

代码语言:javascript复制
abstract class Shape{
    void show(){
        System.out.print("Shape");
    }
}

class Box extends Shape{}

//...

Shape s = new Shape(); // 这个会报错! 不能创建对象
Shape s = new Box(); // 这样是可以的

Java中的密封类是什么?

正如您所看到的,在引入Sealed类之前,继承在Java中是一种要么全有要么全无的事情。并没有中间的规定,这意味着——如果我们希望允许某些类继承其他类无法继承的限制,该怎么办。这种类型的限制性或选择性继承在Sealed类中是可能的。它实际上由两个极端类组成:Final类和Abstract类,前者完全阻止继承,后者强制继承。Sealed类使开发人员能够精确地指定允许哪些子类扩展超级类。

因为有密封类,所以也有密封接口。两者都能更好地控制继承。这在设计类库时特别有用。

程序员可以用关键字Sealed声明一个Sealed类。然后我们提供类名并使用permit子句指定允许的子类。注意,关键字sealed和permissions都是上下文敏感的,并且与类或接口声明相关具有特殊含义;在Java中,它们除了此之外没有任何意义。

Java中的密封类声明如下:

代码语言:javascript复制
public sealed class A permits B, C {
 //...
}

在这个代码示例中,类A可由类B和C继承——或允许继承;没有其他类可以继承它。

代码语言:javascript复制
public final class B extends A { }
public final class C extends A { }
public final class D extends A { } // 这里会报错! D 不能继承 A

注意,允许的类被声明为final。这意味着允许的子类不能进一步继承。然而,除了final关键字之外,我们可以使用其他子句,例如非密封的或与子类密封的。换句话说,密封类的子类必须声明为final、sealed或非sealed。

现在,如果我们希望类B可以由类D进一步扩展,我们可以如下声明D:

代码语言:javascript复制
public sealed class B extends A permits D {}
public final class D extends B {} // 喏,现在可以继承了

现在,假设我们希望类A由B和C扩展,我们也希望类D扩展类B,但我们不希望类D声明为final、非密封或密封,那么我们可以按如下方式设计类:

代码语言:javascript复制
Public sealed class A permits B,C{}
public non-sealed class B extends A { }
public class D extends A { } // OK

密封类的一些关键要求包括:

  • 允许的子类必须可由Sealed类访问。
  • 密封类和子类必须位于同一个命名模块中,尽管它们可以位于不同的包中。
  • 对于未命名的模块,密封类和子类必须在同一个包中。

Java中的密封接口

密封接口的声明方式与密封类几乎相同。这里,permit子句用于指定允许哪个类或接口实现或扩展Sealed接口。例如,我们可以如下声明一个Sealed接口(这里,Sealed接口允许a类和B类实现):

代码语言:javascript复制
public sealed interface SealedInterface permits A, B {}

A class that implements a Sealed interface must be declared as final, sealed, or non-sealed:

代码语言:javascript复制
public non-sealed class A implements SealedInterface{}
public final class B implements SealedInterface{}

如果接口扩展了密封接口,则必须将其声明为密封或非密封。例如:

代码语言:javascript复制
public non-sealed interface AI extends SealedInterface{}

关于Java中密封类的最后思考

Java中Sealed类和接口的引入为Java编程语言的继承特性注入了一些灵活性。尽管它们可能在特殊情况下使用,但密封类可能在API库的类设计中。重点是语言中提供了灵活性;程序员可以根据程序的要求使用它们。这个特性最好的一点是它在继承的使用上带来了某种形式的灵活性,在这种情况下,必须在完全限制继承的Final类之间缩小,或者在必须完全继承的抽象类之间缩小。

今天的分享就到此结束,如果觉得本文不错的还请伙伴们帮忙点赞转发,欢迎持续关注我们!

0 人点赞