【设计模式】Kotlin 与 Java 中的单例
单例模式
单例模式是一个很常见的设计模式,尤其是在 Java 中应用非常广泛。单例模式的定义是保证一个类仅有一个实例,并提供一个访问它的全局访问点。
Java 中的单例模式
Java 中存在多种单例模式的实现方案,最经典的包括:
懒汉式
饿汉式
双重校验锁
饿汉式 / 静态单例
Java 中懒汉式单例如其名一样,“饿” 体现在不管单例对象是否存在,都直接进行初始化:
public final class SingleManager {
@NotNull
public static final SingleManager INSTANCE = new SingleManager();
private SingleManager() {}
public static SingleManager getInstance() {
return INSTANCE;
}
}
实际上,这也是静态单例。
懒汉式 / 延迟初始化
Java 中的懒汉式核心特点在于“懒” ,它不像饿汉式,无论 INSTANCE 是否已经存在值,都进行初始化;而是在调用 get 方法时,检查引用对象是否为空,如果为空再去初始化:
public final class SingleManager {
public static SingleManager INSTANCE;
private SingleManager() {}
public static SingleManager getInstance() {
if (INSTANCE == null) {
INSTANCE = new SingleManager();
}
return INSTANCE;
}
}
双重校验锁
public final class SingleManager {
// volatile 防止指令重排,确保原子操作的顺序性
public volatile static SingleManager INSTANCE;
private SingleManager() {}
public static SingleManager getInstance() {
// 第一次判空,减少进入同步锁的次数,提高效率
if (INSTANCE == null) {
// 确保同步
synchronized (SingleManager.class) {
// 确保加锁后,引用仍是空的
if (INSTANCE == null) {
INSTANCE = new SingleManager();
}
}
}
return INSTANCE;
}
}
Kotlin 中的单例模式
object 关键字
Kotlin 提供了比 Java 更方便的语法糖 object
关键字,能够更方便地实现单例模式:
object SingleManager {
fun main() {}
}
使用:
// used in kotlin
SingleManager.main()
// used in java
SingleManager.Companion.main();
如果要在 Java 中的使用方式与 Kotlin 使用方式一致,可以在方法上添加
@JvmStatic
注解:object SingleManager {
@JvmStatic
fun main() {}
}// used in java
SingleManager.main();
object
关键字实现的单例,编译为 Java 字节码的实现是:
public final class SingleManager {
@NotNull
public static final SingleManager INSTANCE;
public final void main() {
}
private SingleManager() {
}
static {
SingleManager var0 = new SingleManager();
INSTANCE = var0;
}
}
这是一种标准的 Java 静态单例实现。
Kotlin 懒汉式
在一些特殊的情况,例如你的单例对象要保存一些不适合放在静态类中的引用,那么使用 object 就不是合适的方案了,例如,Android 中的上下文 Context 、View 都不适合在静态类中进行引用,IDE 也会提醒你这样会造成内存泄漏:
一种好的解决方案是在 Kotlin 中使用懒汉式的写法:
class SingleManager {
companion object {
private var instance: SingleManager? = null
fun getInstance(): SingleManager {
if (instance == null) {
instance = SingleManager()
}
return instance!!
}
}
var view: View? = null
}
但是这样仍然会提醒你不要引用:
但如果引用的对象是你自定义的 View :
class BaseView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs)
在 kotlin 中懒汉式是不会提示你的:
可以看出,使用 object 关键字,仍然会飘黄,提醒你可能存在内存泄漏。
本质上来说,没有提示实际上也是存在内存泄漏的隐患的。 虽然可以骗过 IDE 但不应该欺骗自己。
写在最后
Kotlin 作为一门更新的 JVM 语言,它提供了很多语法糖突破了 Java 的一些固定写法,有些设计模式已经不再适合新的语言(例如 Builder 模式在 Kotlin 中很少会出现了)。虽然新语言简化了代码的复杂度、简化了写法,但不能简化知识点,例如,使用 Kotlin 需要一个线程安全的单例,仍然可以使用双重校验锁的写法。本质上还是要搞清楚底层逻辑。
链接:https://juejin.cn/post/7200708877389070395
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。