ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

密封类(Sealed Classes):控制类的继承关系(附代码示例)

密封类(Sealed Classes):控制类的继承关系(附代码示例)

在 Java 编程的世界里,类的继承是一项强大的特性,它允许我们创建层次化的类结构,实现代码的复用和扩展。然而,在某些情况下,我们可能希望对类的继承进行更精细的控制,避免类被随意继承和滥用。JDK 17 引入的密封类(Sealed Classes)特性就为我们提供了这样一种解决方案。密封类允许我们明确指定哪些类可以继承某个类,从而增强了代码的安全性和可维护性。接下来,我们就深入了解一下密封类的定义、使用以及如何在实际代码中应用它。

目录

      • 密封类的定义
      • 密封类的使用
      • 密封类在多模块项目中的使用问题及解决方法
        • 模块之间的依赖关系
        • 子类的可见性
      • 代码实战
      • 总结

密封类的定义

密封类是一种特殊的类,它通过sealed关键字进行声明,并且需要指定哪些类可以继承它。在 Java 中,密封类的声明需要满足以下几个条件:

  • 使用sealed关键字:在类的声明中使用sealed关键字,表明这是一个密封类。

    用大白话来讲,sealed关键字就像是一个“门禁系统”,它告诉 Java 编译器,这个类的继承是受到限制的,不是谁都能继承的。

  • 指定允许继承的子类:在密封类的声明中,需要使用permits关键字指定哪些类可以继承该密封类。

    这就好比“门禁系统”里设置了允许进入的人员名单,只有名单上的类才能继承这个密封类。

下面是一个简单的密封类声明示例:

// 声明一个密封类 AnimalpublicsealedclassAnimalpermitsDog,Cat{// 类的成员变量和方法privateStringname;publicAnimal(Stringname){this.name=name;}publicStringgetName(){returnname;}publicvoidmakeSound(){System.out.println("Some generic animal sound");}}// 声明一个继承自 Animal 的子类 DogpublicfinalclassDogextendsAnimal{publicDog(Stringname){super(name);}@OverridepublicvoidmakeSound(){System.out.println("Woof!");}}// 声明一个继承自 Animal 的子类 CatpublicfinalclassCatextendsAnimal{publicCat(Stringname){super(name);}@OverridepublicvoidmakeSound(){System.out.println("Meow!");}}

在这个示例中,Animal类被声明为密封类,使用sealed关键字修饰,并且通过permits关键字指定了Dog和Cat类可以继承它。Dog和Cat类都使用final关键字修饰,这意味着它们不能再被其他类继承。

密封类的使用

密封类的主要作用是控制类的继承范围,确保只有指定的子类可以继承该类。在实际使用中,密封类可以应用于以下场景:

  • 限制类的层次结构:当我们需要构建一个特定的类层次结构,并且不希望其他类随意扩展这个层次结构时,可以使用密封类。

    比如说,我们正在开发一个游戏,游戏中有不同类型的角色,我们希望角色的类型是固定的,不允许外部随意添加新的角色类型,这时就可以使用密封类来定义角色类。

  • 增强代码的安全性:通过限制类的继承,可以避免一些潜在的安全风险,例如恶意子类的创建。

    想象一下,如果一个关键的业务类可以被任意继承,可能会出现恶意子类重写关键方法,从而破坏系统的安全性。使用密封类可以有效避免这种情况。

下面是一个使用密封类的示例代码:

publicclassMain{publicstaticvoidmain(String[]args){// 创建一个 Dog 对象Animaldog=newDog("Buddy");// 调用 Dog 对象的 makeSound 方法dog.makeSound();// 创建一个 Cat 对象Animalcat=newCat("Whiskers");// 调用 Cat 对象的 makeSound 方法cat.makeSound();}}

在这个示例中,我们创建了Dog和Cat类的对象,并调用它们的makeSound方法。由于Dog和Cat类是Animal密封类的子类,所以可以正常创建对象并调用方法。

密封类在多模块项目中的使用问题及解决方法

在多模块项目中使用密封类时,可能会遇到一些问题,例如模块之间的依赖关系、子类的可见性等。下面我们来详细分析这些问题并给出解决方法。

模块之间的依赖关系

当密封类和它的子类分布在不同的模块中时,需要确保模块之间有正确的依赖关系。如果模块之间的依赖关系不正确,编译器可能无法找到密封类允许继承的子类,从而导致编译错误。

解决方法:在module-info.java文件中正确声明模块之间的依赖关系。例如,如果sealed-module模块包含密封类,subclass-module模块包含密封类的子类,那么subclass-module模块需要依赖sealed-module模块。

// sealed-module/module-info.javamodulesealedModule{exportscom.example.sealed;}// subclass-module/module-info.javamodulesubclassModule{requiressealedModule;exportscom.example.subclass;}
子类的可见性

在多模块项目中,密封类的子类需要对使用密封类的模块可见。如果子类的可见性不正确,编译器可能无法找到子类,从而导致编译错误。

解决方法:确保密封类的子类在模块中是可导出的,并且在permits关键字中指定的子类名称是正确的。例如,在上面的示例中,Dog和Cat类所在的包需要在模块中导出。

代码实战

下面我们通过一个完整的代码示例来展示密封类的声明、继承和使用。

// 声明一个密封类 ShapepublicsealedclassShapepermitsCircle,Rectangle{publicabstractdoublearea();}// 声明一个继承自 Shape 的子类 CirclepublicfinalclassCircleextendsShape{privatedoubleradius;publicCircle(doubleradius){this.radius=radius;}@Overridepublicdoublearea(){returnMath.PI*radius*radius;}}// 声明一个继承自 Shape 的子类 RectanglepublicfinalclassRectangleextendsShape{privatedoublelength;privatedoublewidth;publicRectangle(doublelength,doublewidth){this.length=length;this.width=width;}@Overridepublicdoublearea(){returnlength*width;}}// 测试类publicclassShapeTest{publicstaticvoidmain(String[]args){// 创建一个 Circle 对象Shapecircle=newCircle(5);System.out.println("Circle area: "+circle.area());// 创建一个 Rectangle 对象Shaperectangle=newRectangle(4,6);System.out.println("Rectangle area: "+rectangle.area());}}

在这个示例中,我们声明了一个密封类Shape,并指定了Circle和Rectangle类可以继承它。Circle和Rectangle类都实现了Shape类的area方法,用于计算图形的面积。在ShapeTest类的main方法中,我们创建了Circle和Rectangle类的对象,并调用它们的area方法输出面积。

总结

通过学习密封类的定义和使用,我们可以在代码中合理使用密封类来控制类的继承关系。密封类的核心价值在于增强了代码的安全性和可维护性,通过限制类的继承范围,避免了类的滥用和潜在的安全风险。同时,密封类在多模块项目中的使用需要注意模块之间的依赖关系和子类的可见性。

掌握了密封类的内容后,下一节我们将深入学习 JDK 17 的其他新语法特性,进一步完善对本章 JDK 17 新语法特性实战主题的认知。


🍃 程序员JDK17修炼手册系列专栏导航

建议按系列顺序阅读,从基础到进阶逐步掌握JDK核心能力,避免遗漏关键知识点~

  • 🔖 专栏目录:JDK17新特性

系列文章衔接

  • 🔖 JDK5新特性

  • 🔖 JDK8新特性

  • 🔖 JDK11新特性

  • 🔖 JDK21新特性

  • 🍃 博客概览:《程序员技术成长导航,专栏汇总》

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进