kotlin - 我应该使用 Object 还是文件级 val 创建单例?
问题描述
我们希望有一个将在整个代码库中使用的类的单个实例。我们创建了一个专用包来保存这个实例。如果我理解正确的话,有两种方法可以声明单例。
(示例使用Jackson
,但这并不是以任何方式特定的。)
目的
package net.goout.jackson
import com.fasterxml.jackson.databind.ObjectMapper
...
object Jackson : ObjectMapper() {
init {
configure(...)
}
}
文件级val
package net.goout.jackson
import com.fasterxml.jackson.databind.ObjectMapper
...
val jackson = ObjectMapper().apply {
configure(...)
}
在这两种情况下,只创建了一个实例,并且调用站点相同(除了命名略有不同)。
这两种方法有什么实际区别吗?
解决方案
我无法发现任何实际差异,不!
查看生成的字节码会发现这两种情况比您想象的更相似:都有一个静态初始化器和一个字段。主要区别在于,object
如果它们在新类中并且字段 ( INSTANCE
) 是公共的,而在这种var
情况下它是私有的并且通过名为 的隐藏类中的 getter 方法访问…Kt
。(实际上,无论如何,getter 通常都会得到优化。)这可能会影响初始化顺序,但这在这里无关紧要。
在语言层面,object
版本会创建一个新的子类,而val
版本不会——所以你可能会认为后者稍微“更纯粹”,尽管我看不出这对你有什么影响。如果你从 Java 调用,这两种情况会有不同的复杂性——尽管问题只提到了 Kotlin。
而且val
版本略短且简单——只有一点点优势,但在没有任何其他因素的情况下,简洁和简单是好事!
顺便说一句,问题假设该configure()
方法是“流利的”,即返回调用它的对象。但即使没有,您也可以通过简单地将其包围在apply()
调用中来获得相同的效果。
推荐阅读
- r - 当 parallel 为 TRUE 时,auto.arima() 函数比从未使用时慢
- arrays - JQ 连接两个数组
- java - org.gradle.tooling.internal.gradle.DefaultBuildIdentifier 类未实现请求的接口
- reactjs - reactjs和更新数组的状态
- python-3.x - 在下面给出的python代码中发出的熊猫数据框错误
- sails.js - 您可以使用 Sails Policies 根据 req 变量将请求重定向到相应的控制器吗?
- python-3.x - 网络爬虫尝试
- android - 在移动设备上进行声音识别训练是否可行?
- html - 有没有办法确定嵌入响应视频元素中视频边距的高度和宽度?
- javascript - 跟踪/调试大型 Javascript DHTML 页面