重要辨析:non-sealed不是默认行为。在一个sealed类的继承体系中,如果你不显式声明子类的状态,编译会失败。non-sealed不等于普通的publicclass。 non-sealed无限(可被任意类继承)在密封体系中有选择地开放某个分支。密封类子类的特殊状态,用于打破密封。 sealed和non-sealed不适用于static成员,因为它们只关心类的继承关系。 第四部分:常见误区与最佳实践4.1误区澄清误区:“non-sealed就是普通的publicclass。” 谨慎使用non-sealed:它是一个强大的工具,但也可能破坏密封体系的初衷。只在确实需要开放某个特定分支时才使用它。
sealed 修饰的类的机制具有传递性,它的子类必须使用指定的关键字进行修饰,且只能是 final、sealed、non-sealed 三者之一。 final:子类为finall,间接表示父类不能被其他类继承 sealed:子类也可以声明为密封类 non-sealed:声明为非密封类,可以被其他类继承 举例: public abstract sealed //子类也是一个密封类 public non-sealed class Square extends Shape {...} //non-sealed表示子类不是一个密封类,可以被任何类继承
其中最为笔者印象深刻的莫过于对于——密封类可以被继承 密封类从刚开始学就从各种途径了解到不能被继承,新版本的密封类如果想要被继承需要用permits指定被继承的类 同时,被继承的类需要用final,sealed或者non-sealed classRailWayWorkerextendsWorker{ } //铁路工人 这时如果想让密封类被继承就需要用permits指定被继承的类,被继承的类如果没有final,sealed或者non-sealed
答案是否定的,只需要使用关键字non-sealed显式声明密封类的继承实现为非密封类就可以继续扩展了。 public non-sealed class SealedServiceImpl implements SealedService { @Override public void doSomething () { } /** * 用{@code non-sealed}声明非密封类,就可以继续扩展了 */ static class NonSealedExtend extends SealedServiceImpl { } } 总结一下,密封类的子类要么是final Class;要么是sealed Class;要么是non-sealed Class
继承者只能是 final(断绝后代)、sealed(继续指定继承人)或 non-sealed(开放继承,等于不用sealed修饰,但是不能省略)。 正统皇帝也可以宣布不传位给儿子们 non-sealed不再世袭罔替 实际作用 严格管控继承:避免类被随意扩展,破坏设计。 增强可读性:一看 permits 就知道有哪些子类。 Override public void dead() { System.out.println("Yongzheng dead"); }}//子类实现 不限制继承public non-sealed
新手段:密封类 为了进一步增强限制能力,Java 17中的密封类增加了几个重要关键词: sealed:修饰类/接口,用来描述这个类/接口为密封类/接口 non-sealed:修饰类/接口,用来描述这个类 完成这个改造之后,我们会发现TankHero, AttackHero, SupportHero这三个类开始报错了,具体错误如下: sealed, non-sealed or final modifiers expected 这是因为父类Hero被sealed修饰之后,sealed的密封要求被传递过来,此时子类就必须在sealed、non-sealed、final之间选择一个定义,它们分别代表: sealed :继续延续密封类特性,可以继续指定继承的类,并传递密封定义给子类 non-sealed:声明这个类为非密封类,可以被任意继承 final:不允许继承 根据上面的假设需求,第一、第二层稳定,允许第三层具体英雄角色可以后期不断增加新英雄 ,所以三类抽象英雄的定义可以这样编写: public non-sealed class TankHero extends Hero { } 而对于第三层的英雄角色,已经是最后的具体实现,则可以使用final
但是继承的类也需要被密封,可以使用final,sealed,non-sealed。 这里很有意思,给Dog加了sealed还是报错了。 刚才不是还说“继承的类也需要被密封,可以使用final,sealed,non-sealed。”吗?注意,这个时候报错原因不一样了,因为Dog也被sealed修饰了,所以也需要子类。 或者改成non-sealed或者final。 重点总结: sealed修饰的类必须要有⼦类 使⽤ non-sealed 关键字修饰。表⽰不限制,任何类都可以继承。 void eat() { System.out.println("eat()...."); } } sealed class Cat extends Animal permits OrgCat{ } non-sealed
TestSealedClass { } /*sealed 对Person类进行密封 * permits 指明哪些类可以继承 * 子类必须是final修饰的或者也是密封的 * 如果子类不想被密封,可以使用non-sealed final class PrimaryStudent extends Student{} final class GraduateStudent extends Student{} // 通过non-sealed 取消子类密封 non-sealed class Worker extends Person{} class CarWorker extends Worker{} sealed interface Myinter2 permits Myinter3 {} sealed interface Myinter3 extends Myinter1,Myinter2{} non-sealed {} sealed interface I permits A,B,C {} final class A implements I{} sealed class B implements I{} non-sealed
和C扩展,我们也希望类D扩展类B,但我们不希望类D声明为final、非密封或密封,那么我们可以按如下方式设计类: Public sealed class A permits B,C{} public non-sealed SealedInterface permits A, B {} A class that implements a Sealed interface must be declared as final, sealed, or non-sealed : public non-sealed class A implements SealedInterface{} public final class B implements SealedInterface 例如: public non-sealed interface AI extends SealedInterface{} 关于Java中密封类的最后思考 Java中Sealed类和接口的引入为Java
需要注意,父类被定义为 sealed 之后,子类必须是 sealed、 non-sealed 或者 final。 public abstract sealed class Animal permits Cat, Dog { public abstract void eat(); } public non-sealed Animal{ @Override public void eat() { System.out.println("dog eat"); } } public non-sealed
在Jdk17中通过密封类可以解决这个问题,主要就这几个关键字: final:不允许被继承 sealed:密封类(需要指定哪个类可以扩展它) non-sealed:可以被任何类继承 permits :指定哪个类可以继承于我 这里做个小测试,创建一个BigDog类并继承Dog: 图片 直接告诉你 密封层次结构中不允许使用"BigDog" ,需要给BigDog指定这个permits ,其他亦是如此,除非你定义成non-sealed :密封类的子类必须是 final类、sealed类或non-sealed类,并且 父类和子类 必须在同一个包下 开始安装 下载安装可以参考我之前的文章:《Jdk17安装+环境配置详细教程【Windows
sealed写在原来final的位置,但是不能和final、non-sealed关键字同时出现,只能选择其一。 继承的子类必须显式标记为final、sealed或是non-sealed类型。 类名 [extends 父类] [implements 接口, ...] permits [子类, ...]{ //里面的该咋写咋写 } 子类格式为: public [final/sealed/non-sealed //non-sealed类型:重新开放为普通类,任何类都可以继承。 类名 [extends 父类] [implements 接口, ...] permits [子类, ...]{ //里面的该咋写咋写 } 子类格式为: public [final/sealed/non-sealed //non-sealed类型:重新开放为普通类,任何类都可以继承。
Java17 引入一对新的关键词:sealed 与 non-sealed 以及与之配套使用的 permits 关键字。 final class Cat extends Pet {} 3.2 在子类上解除密封 如果我们只是不想让任何类直接派生自 Pet 类,但却允许让 Cat 和 Dog 拥有各自的子类,那么,我们就可以使用 non-sealed 关键字来解开限制: public non-sealed class Dog extends Pet {} 4.
abstract sealed class Person permits Employee, Manager { //... } 另外,任何扩展密封类的类本身都必须声明为 sealed、non-sealed public final class Employee extends Person { } public non-sealed class Manager extends Person { }
TransparentRectangle extends Rectangle {...}public final class FilledRectangle extends Rectangle {...}public non-sealed 这里使用了3个关键字,一个是sealed,一个是permits,一个是non-sealed;permits的这些子类要么使用final,要么使用sealed,要么使用non-sealed修饰;针对record
public non-sealed class Square extends Shape {...} 这里使用了3个关键字,一个是sealed,一个是permits,一个是non-sealed;permits的这些子类要么使用final,要么使用sealed,要么使用non-sealed修饰;针对record
public non-sealed class MarryPlayer extends SealedPlayer{ @Override public void play() { 比如这个例子中是用的 non-sealed,表示不限制,任何类都可以继承,还可以是 sealed,或者 final。 允许的类型,则没办法继承,比如下面这个,编译不过去,会给出提示 "java: 类不得扩展密封类:org.jdk17.SealedPlayer(因为它未列在其 'permits' 子句中)" public non-sealed
三选一, 第一种:sealed,就是你自己也称为密封类,这样子类还是受限制的 第二种:non-sealed,就是明确告诉大家,你不是密封类,而且不是 final,这意味着 Playing 这个类型是可以被其他类型继承的 这么看来,Java 除了支持密封接口以外,也是直接密封类的,而且还能允许密封接口或者密封类的 non-sealed 子类有其他子类,看上去是不是比 Kotlin 高级? 非也非也!
而且 sealed 修饰的类的机制具有传递性,它的子类必须使用指定的关键字进行修饰,且只能是 final、sealed、non-sealed 三者之一。 @author www.wdbyte.com */ public final class BorderCollie extends Collie{ } 田园犬(ToGou)可以被任意继承,使用 non-sealed package com.wdbyte; /** * @author niulang */ public non-sealed class TuGou implements Dog { } JEP371
final class C extends Root { ... } } 对于密封类的子类来讲,既可以声明为 final 来禁止被继承;也可以声明为 sealed 来使得该子类的直接子类可数;也可以声明为 non-sealed static final class B1 extends B {} static final class B2 extends B {} } static non-sealed