资讯详情

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

📅 2026/10/23 4:21:40 | 华诺云谱 👁 阅读
密封类(Sealed Classes):控制类的继承关系(附代码示例)
在 Java 编程的世界里类的继承是一项强大的特性它允许我们创建层次化的类结构实现代码的复用和扩展。然而在某些情况下我们可能希望对类的继承进行更精细的控制避免类被随意继承和滥用。JDK 17 引入的密封类Sealed Classes特性就为我们提供了这样一种解决方案。密封类允许我们明确指定哪些类可以继承某个类从而增强了代码的安全性和可维护性。接下来我们就深入了解一下密封类的定义、使用以及如何在实际代码中应用它。目录密封类的定义密封类的使用密封类在多模块项目中的使用问题及解决方法模块之间的依赖关系子类的可见性代码实战总结密封类的定义密封类是一种特殊的类它通过sealed关键字进行声明并且需要指定哪些类可以继承它。在 Java 中密封类的声明需要满足以下几个条件使用sealed关键字在类的声明中使用sealed关键字表明这是一个密封类。用大白话来讲sealed关键字就像是一个“门禁系统”它告诉 Java 编译器这个类的继承是受到限制的不是谁都能继承的。指定允许继承的子类在密封类的声明中需要使用permits关键字指定哪些类可以继承该密封类。这就好比“门禁系统”里设置了允许进入的人员名单只有名单上的类才能继承这个密封类。下面是一个简单的密封类声明示例// 声明一个密封类 AnimalpublicsealedclassAnimalpermitsDog,Cat{// 类的成员变量和方法privateStringname;publicAnimal(Stringname){this.namename;}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 对象AnimaldognewDog(Buddy);// 调用 Dog 对象的 makeSound 方法dog.makeSound();// 创建一个 Cat 对象AnimalcatnewCat(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.radiusradius;}Overridepublicdoublearea(){returnMath.PI*radius*radius;}}// 声明一个继承自 Shape 的子类 RectanglepublicfinalclassRectangleextendsShape{privatedoublelength;privatedoublewidth;publicRectangle(doublelength,doublewidth){this.lengthlength;this.widthwidth;}Overridepublicdoublearea(){returnlength*width;}}// 测试类publicclassShapeTest{publicstaticvoidmain(String[]args){// 创建一个 Circle 对象ShapecirclenewCircle(5);System.out.println(Circle area: circle.area());// 创建一个 Rectangle 对象ShaperectanglenewRectangle(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新特性 博客概览《程序员技术成长导航专栏汇总》
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑