Kotlin 真香之密封类
痛点
不知道大家,有没有在 Java 中做过这样的事情,申明一个枚举,在枚举中定义各种值,其中他们各自在构造函数中做不同的初始化工作。
1 | public enum Color { |
这样的好处在于,限定死了 Color 的种类,在具体使用时直接用就好,Enum 这种方式,有个最大的难题在于,所以不能控制对象的构建时机,当类构建时 Color 中的各种子类也必须构建好。另一方面,如果通过类继承的方式来做的话,因为无法限制范围,你想实现多少个就多少个,代码可能需要用到 instanceof
这个关键字,Java 老师告诉我们一般出现这个关键字,大概率代码中出现了异味。
Usage
kotlin 语言的研发者,也发现了这个问题,于是给我们封装一个语法糖sealed
,中文学名也就密封类。密封类结合了两者的优点,同时避免了两者的缺点。
我们来看看具体的例子,特别简单。
1 | sealed class Fruit |
注意三者都在一个文件中。将一个类申明为 sealed 之后,只能在同样的文件中定义其子类,在其他地方无法构建其子类,也就是说 Fruit 的子类,被完全限定在这个文件中了。
1 | class Pear: Fruit() |
如果我们尝试在另一个文件中,继承 Fruit 实现另一个类的话,会编译不过,提示构造函数 not accessable。这样就帮助我们即限定了范围,又不影响我们的构造时机,实乃天赐良方呀。
Under in hood
还是和上一篇文章一样,我们通过反编译的方式来看看,背后的原理是怎样的,会不会同样大吃一惊。
1 | // Fruit.java |
我们看到对于 sealed 修饰的类,实现一个私有的构造函数,同时添加了一个 public 的构造函数,里面有一个 DefaultConstructorMarker
的参数。咦?那我们岂不是可以在外界通过这个 public 的构造函数来申明新的对象?这个地方就是 kotlin 编译器为我们做的限制,DefaultConstructorMarker 是 kotlin internal 的,kotlin 限制 internal 中对象不能被外部访问。
这就是 sealed class 的秘密!
额外,留一个问题,如果 Fruit 类构造函数里面,有一个 参数,情况会有所不同吗?原理是什么?
文档信息
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
- 发表日期:2019年09月15日
- 社交媒体:weibo.com/woaitqs
- Feed订阅:www.woaitqs.cc/atom.xml