单例形式
单例形式是一个很常见的规划形式,尤其是在 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 需要一个线程安全的单例,依然能够运用两层校验锁的写法。本质上还是要搞清楚底层逻辑。