密封类在 Java SE 15 中首次预览,此功能在 Java SE 17 版本中是永久性的。这意味着它可以在为 Java SE 17 编译的任何程序中使用,而无需启用预览功能。
密封类
你定义了一个 Person 类,但是有只 Dog 想继承这个 Person 类,这还得了?狗子就是狗子,怎么能有人的行为捏?这只狗子想干嘛!要成精不成,妖孽还不现出原型!对于狗子想要继承人行为的这种做法必须达咩,身为人类的我们必须阻止这种行为!!!
1. 声明密封类
通过密封一个类,可以指定允许哪些类扩展它,并防止任何其他任意类这样做想,这就需要用到 sealed
修饰符去修饰这个类为密封类
,然后需要在类名后边使用 permits
子句去指定可以扩展的子类。请看如下代码:
Person:人类
public sealed class Person permits Worker {
// 姓名
String name;
// 年龄
int age;
// 母语
String motherTongue;
}
Worker:工人
public sealed class Worker extends Person permits Cleaner, Programmer {
// 职业
String profession;
// 工资
double money;
// 工作地
String workGround;
}
Programmer:程序员
public final class Programmer extends Worker {
// 语言
String language;
// 键盘
String keyboard;
}
看到上边这三段代码,能不能注意到什么?
sealed
不仅仅可以修饰父类,也可以修饰子类,子类也是可以有子类的。就像爷爷、爸爸与你的关系。- 子类使用
permits
子句前一定要先继承他的父类,否则会报错,除非他仅仅当一个父类。- 当一个类仅作为子类继承
sealed
修饰的父类时,子类必须使用final
修饰为最终类。- 子类必须在编译时可由父类访问,说人话就是,子类存在才行。
permits
是必须存在的,且必须指定子类。
墨菲定律告诉我们:“你越害怕发生的事,越会发生”
。既然有密封类,就要有非密封类,因为你不知道事情发展的方向,请看如下代码:
Cleaner:清洁工
public non-sealed class Cleaner extends Worker {
// 工种
String typeOfWork;
}
StreetCleaner:马路清洁工
public class StreetCleaner extends Cleaner {
}
在
Cleaner
类中 使用non-sealed
修饰符来修饰这个类为非密封类
,你不需要在非密封类中使用permits
指定子类,因为他可以被任何类所继承,就像StreetCleaner
类继承StreetCleaner
一样,而且你不需要将这个子类修饰为final
的。
Person:人类
public sealed class Person {
// 姓名
String name;
// 年龄
int age;
// 母语
String motherTongue;
}
sealed class Worker extends Person {
// 职业
String profession;
// 工资
double money;
// 工作地
String workGround;
}
non-sealed class Cleaner extends Worker {
// 工种
String typeOfWork;
}
class StreetCleaner extends Cleaner {
}
final class Programmer extends Worker {
// 语言
String language;
// 键盘
String keyboard;
}
在上边代码中,如果你将之前的所有类都放在与密封类相同的文件中,那么使用
sealed
修饰的类 就不需要使用permits
指定子类。
注意:
子类想要继承密封类必须与密封类位于同一包中
2. 声明密封接口
与密封类一样,要密封接口,需要使用
sealed
修饰符修饰接口。然后添加permits
子句,它指定可以实现密封接口的类以及可以扩展密封接口的接口。
下面请看 Oracle 官网的一个案例:
Expressions:表达式
public class Expressions {
public static void main(String[] args) {
System.out.println(
new TimesExpr(new PlusExpr(new ConstantExpr(6), new ConstantExpr(7)),
new NegExpr(new ConstantExpr(8))).eval());
}
}
sealed interface Expr permits ConstantExpr, PlusExpr, TimesExpr, NegExpr {
public int eval();
}
final class ConstantExpr implements Expr {
int i;
ConstantExpr(int i) {
this.i = i;
}
@Override
public int eval() {
return i;
}
}
final class PlusExpr implements Expr {
Expr a, b;
PlusExpr(Expr a, Expr b) {
this.a = a;
this.b = b;
}
@Override
public int eval() {
return a.eval() * b.eval();
}
}
final class TimesExpr implements Expr {
Expr a, b;
TimesExpr(Expr a, Expr b) {
this.a = a;
this.b = b;
}
@Override
public int eval() {
return a.eval() * b.eval();
}
}
final class NegExpr implements Expr {
Expr e;
NegExpr(Expr e) {
this.e = e;
}
@Override
public int eval() {
return -e.eval();
}
}