单例形式

单例形式是一个很常见的规划形式,尤其是在 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 与 Java 中的单例

一种好的解决方案是在 Kotlin 中运用懒汉式的写法:

class SingleManager {
    companion object {
        private var instance: SingleManager? = null
        fun getInstance(): SingleManager {
            if (instance == null) {
                instance = SingleManager()
            }
            return instance!!
        }
    }
    var view: View? = null
}

可是这样依然会提示你不要引证:

【设计模式】Kotlin 与 Java 中的单例

但假如引证的目标是你自界说的 View :

class BaseView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs)

在 kotlin 中懒汉式是不会提示你的:

【设计模式】Kotlin 与 Java 中的单例

能够看出,运用 object 关键字,依然会飘黄,提示你可能存在内存走漏。

本质上来说,没有提示实际上也是存在内存走漏的隐患的。 尽管能够骗过 IDE 但不应该诈骗自己。

写在最后

Kotlin 作为一门更新的 JVM 言语,它供给了许多语法糖突破了 Java 的一些固定写法,有些规划形式现已不再适合新的言语(例如 Builder 形式在 Kotlin 中很少会呈现了)。尽管新言语简化了代码的复杂度、简化了写法,但不能简化知识点,例如,运用 Kotlin 需要一个线程安全的单例,依然能够运用两层校验锁的写法。本质上还是要搞清楚底层逻辑。