首先密封类可以看作是 枚举,为 继承 设计的,是一个抽象类。
因为是抽象类,所以不能实例化,只能实例化其子类。
更多的在于限制继承,起到划分子类的作用,规定了有限个类型,不可以存在其他任何类型。(即子类是确定的,不存在子类以外的类型)
与枚举类的区别是 枚举类只能有一个实例,而密封类的子类可以有多个实例 ,可以视为枚举类的一个拓展。
使用场景
禁止外部继承,对于一些只划分固定类型的数据,保证安全。
-
when遍历密封类的子类时,不用加else语句。(主要解决了when结构需要添加一个默认的else分支的问题)
如果添加了一个新的分支,编译器无法发现有的地方发生了改变。
如果忘记了添加这个新的分支,就会选择默认选项,所以有隐藏bug。
关于修饰符
sealed修饰符隐含了这个类是一个open类,不需要显试添加open修饰符。
因为密封类是一个抽象类,不能用data等非抽象类的修饰符来修饰。
声明的位置
密封类的所有子类必须在密封类自身相同的文件中声明 或 密封类内部声明。
kotlin密封类
两种写法对比:
- 子类写在同一个文件中:
// kotlin代码
sealed class SealedDemo(val id: String)
class ChildSealed(id: String): SealedDemo(id)
class ChildSealed2(id: String): SealedDemo(id)
// java代码
// SealedDemo.java
public abstract class SealedDemo {
@NotNull
private final String id;
@NotNull
public final String getId() {
return this.id;
}
private SealedDemo(String id) {
this.id = id;
}
public SealedDemo(String id, DefaultConstructorMarker $constructor_marker) {
this(id);
}
}
// ChildSealed.java
public final class ChildSealed extends SealedDemo {
public ChildSealed(@NotNull String id) {
Intrinsics.checkParameterIsNotNull(id, "id");
super(id, (DefaultConstructorMarker)null);
}
}
// ChildSealed2.java
public final class ChildSealed2 extends SealedDemo {
public ChildSealed2(@NotNull String id) {
Intrinsics.checkParameterIsNotNull(id, "id");
super(id, (DefaultConstructorMarker)null);
}
}
- 子类写在密封类内部:
// kotlin代码
sealed class SealedDemo(val id: String) {
class ChildSealed(id: String): SealedDemo(id)
class ChildSealed2(id: String): SealedDemo(id)
}
// java代码
public abstract class SealedDemo {
@NotNull
private final String id;
@NotNull
public final String getId() {
return this.id;
}
private SealedDemo(String id) {
this.id = id;
}
public SealedDemo(String id, DefaultConstructorMarker $constructor_marker) {
this(id);
}
// 静态内部类
public static final class ChildSealed extends SealedDemo {
public ChildSealed(@NotNull String id) {
Intrinsics.checkParameterIsNotNull(id, "id");
super(id, (DefaultConstructorMarker)null);
}
}
// 静态内部类
public static final class ChildSealed2 extends SealedDemo {
public ChildSealed2(@NotNull String id) {
Intrinsics.checkParameterIsNotNull(id, "id");
super(id, (DefaultConstructorMarker)null);
}
}
}
差别就是写在内部会被编译成静态内部类。