Kotlin和Java 单例模式

简介: Kotlin和Java 单例模式

Java 和Kotlin的单例模式其实很像,只是Kotlin一部分单例可以用对象类和委托lazy来实现

Java

/**
 * 懒汉式,线程不安全
 */
class Singleton {
    private static Singleton instance;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
 
/**
 * 懒汉式,线程安全
 */
class Singleton1 {
    private static Singleton1 instance;
    private Singleton1() {
    }
    public static synchronized Singleton1 getInstance() {
        if (instance == null) {
            instance = new Singleton1();
        }
        return instance;
    }
}
 
/**
 * 饿汉式
 */
class Singleton2 {
    private static Singleton2 instance = new Singleton2();
    private Singleton2() {
    }
    public static Singleton2 getInstance() {
        return instance;
    }
}
 
/**
 * 双检锁/双重校验锁(DCL,即 double-checked locking)
 */
class Singleton3 {
    private volatile static Singleton3 singleton;
    private Singleton3() {
    }
    public static Singleton3 getSingleton() {
        if (singleton == null) {
            synchronized (Singleton3.class) {
                if (singleton == null) {
                    singleton = new Singleton3();
                }
            }
        }
        return singleton;
    }
}
 
/**
 * 登记式/静态内部类
 */
class Singleton4 {
    private static class SingletonHolder {
        private static final Singleton4 INSTANCE = new Singleton4();
    }
    private Singleton4() {
    }
    public static final Singleton4 getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
 
/**
 * 枚举
 */
enum Singleton5 {
    INSTANCE2;
    public void whateverMethod() {
        System.out.println("....");
    }
}

Kotlin

/**
 * 懒汉式,线程不安全,仿Java
 */
internal class Singleton6 private constructor() {
    companion object {
        private var instance: Singleton6? = null
 
        fun getInstance(): Singleton6 {
            if (instance == null) {
                instance = Singleton6()
            }
            return instance!!
        }
    }
}
 
/**
 * 懒汉式,线程不安全
 */
internal class Singleton7 private constructor() {
    companion object {
        var instance: Singleton7? = null
            get() {
                if (field == null) {
                    field = Singleton7()
                }
                return field
            }
 
    }
}
 
/**
 * 懒汉式,线程安全
 */
internal class Singleton8 private constructor() {
    companion object {
        @get:Synchronized
        var instance: Singleton8? = null
            get() {
                if (field == null) {
                    field = Singleton8()
                }
                return field
            }
    }
}
 
/**
 *饿汉式
 */
internal object Singleton9 {
    fun whateverMethod() {
        println("....")
    }
}
 
/**
 *饿汉式,仿Java
 */
internal class Singleton10 private constructor() {
    companion object {
        val instance = Singleton10()
    }
}
 
/**
 * 双检锁/双重校验锁(DCL,即 double-checked locking)
 */
internal class Singleton12 private constructor() {
    companion object {
        val instance: Singleton12 by lazy {
            Singleton12()
        }
    }
}
 
/**
 * 双检锁/双重校验锁(DCL,即 double-checked locking),仿Java
 */
internal class Singleton11 private constructor() {
    companion object {
        @Volatile
        var instance: Singleton11? = null
            get() {
                if (field == null) {
                    synchronized(Singleton11::class) {
                        if (field == null) {
                            field = Singleton11()
                        }
                    }
                }
                return field
            }
    }
}
 
/**
 * 登记式/静态内部类
 */
internal class Singleton13 {
    private object SingletonHolder {
        val INSTANCE = Singleton13()
    }
 
    companion object {
        val instance: Singleton13
            get() = SingletonHolder.INSTANCE
    }
}
 
/**
 * 枚举
 */
internal enum class Singleton14 {
    INSTANCE;
 
    fun whateverMethod() {
        println("....")
    }
}

Kotlin的5种单例模式

前言

最近在学习Kotlin这门语言,在项目开发中,运用到了单例模式。因为其表达方式与Java是不同的。所以对不同单例模式的实现进行了分别探讨。主要单例模式实现如下:

  • 饿汉式
  • 懒汉式
  • 线程安全的懒汉式
  • 双重校验锁式
  • 静态内部类式

PS:该篇文章不讨论单例模式的运用场景与各种模式下的单例模式的优缺点。只讨论在Java下不同单例模式下的对应Kotlin实现。

一、饿汉式实现

//Java实现
public class SingletonDemo {
    private static SingletonDemo instance=new SingletonDemo();
    private SingletonDemo(){
 
    }
    public static SingletonDemo getInstance(){
        return instance;
    }
}
//Kotlin实现
object SingletonDemo

这里很多小伙伴就吃了一惊。我靠,一个object 关键字就完成相同的功能?一行代码?

Kotlin的对象声明

学习了Kotlin的小伙伴肯定知道,在Kotlin中类没有静态方法。如果你需要写一个可以无需用一个类的实例来调用,但需要访问类内部的函数(例如,工厂方法,单例等),你可以把该类声明为一个对象。该对象与其他语言的静态成员是类似的。如果想了解Kotlin对象声明的更多内容,可以去看看之前的文章。

到这里,如果还是有很多小伙伴不是很相信一行代码就能解决这个功能,我们可以通过一下方式查看Kotlin的字节码。

查看Kotlin对应字节码

 

我们进入我们的Android Studio(我的Android Studio 3.0,如果你的编译器版本过低,请自动升级) 选择Tools工具栏,选择"Kotlin",选择“Show Kotlin Bytecode"

选择过后就会进入到下方界面:

点击"Decompile" 根据字节码得到以下代码:

public final class SingletonDemo {
   public static final SingletonDemo INSTANCE;
   private SingletonDemo(){}
   static {
      SingletonDemo var0 = new SingletonDemo();
      INSTANCE = var0;
   }
}

通过以上代码,我们了解事实就是这个样子的,使用Kotlin"object"进行对象声明与我们的饿汉式单例的代码是相同的。

二、懒汉式

//Java实现
public class SingletonDemo {
    private static SingletonDemo instance;
    private SingletonDemo(){}
    public static SingletonDemo getInstance(){
        if(instance==null){
            instance=new SingletonDemo();
        }
        return instance;
    }
}
//Kotlin实现
class SingletonDemo private constructor() {
    companion object {
        private var instance: SingletonDemo? = null
            get() {
                if (field == null) {
                    field = SingletonDemo()
                }
                return field
            }
        fun get(): SingletonDemo{
        //细心的小伙伴肯定发现了,这里不用getInstance作为为方法名,是因为在伴生对象声明时,内部已有getInstance方法,所以只能取其他名字
         return instance!!
        }
    }
}

上述代码中,我们可以发现在Kotlin实现中,我们让其主构造函数私有化并自定义了其属性访问器,其余内容大同小异。

三、线程安全的懒汉式

//Java实现
public class SingletonDemo {
    private static SingletonDemo instance;
    private SingletonDemo(){}
    public static synchronized SingletonDemo getInstance(){//使用同步锁
        if(instance==null){
            instance=new SingletonDemo();
        }
        return instance;
    }
}
//Kotlin实现
class SingletonDemo private constructor() {
    companion object {
        private var instance: SingletonDemo? = null
            get() {
                if (field == null) {
                    field = SingletonDemo()
                }
                return field
            }
        @Synchronized
        fun get(): SingletonDemo{
            return instance!!
        }
    }
 
}

大家都知道在使用懒汉式会出现线程安全的问题,需要使用使用同步锁,在Kotlin中,如果你需要将方法声明为同步,需要添加@Synchronized注解。

四、双重校验锁式(Double Check)

//Java实现
public class SingletonDemo {
    private volatile static SingletonDemo instance;
    private SingletonDemo(){} 
    public static SingletonDemo getInstance(){
        if(instance==null){
            synchronized (SingletonDemo.class){
                if(instance==null){
                    instance=new SingletonDemo();
                }
            }
        }
        return instance;
    }
}
//kotlin实现
class SingletonDemo private constructor() {
    companion object {
        val instance: SingletonDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        SingletonDemo() }
    }
}

小伙伴们惊不惊喜,感不感动啊。我们居然几行代码就实现了多行的Java代码。其中我们运用到了Kotlin的延迟属性 Lazy。

Lazy是接受一个 lambda 并返回一个 Lazy 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果,后续调用 get() 只是返回记录的结果。

这里还有有两个额外的知识点。

  • 高阶函数,高阶函数是将函数用作参数或返回值的函数。大家还是看这个 --- 高阶函数
  • 委托属性

五、静态内部类式

//Java实现
public class SingletonDemo {
    private static class SingletonHolder{
        private static SingletonDemo instance=new SingletonDemo();
    }
    private SingletonDemo(){
        System.out.println("Singleton has loaded");
    }
    public static SingletonDemo getInstance(){
        return SingletonHolder.instance;
    }
}
//kotlin实现
class SingletonDemo private constructor() {
    companion object {
        val instance = SingletonHolder.holder
    }
 
    private object SingletonHolder {
        val holder= SingletonDemo()
    }
}

静态内部类的实现方式,也没有什么好说的。Kotlin与Java实现基本雷同。

六、补充

那么如果小伙伴问,如何在Kotlin版的Double Check,给单例添加一个属性,这里给大家提供了一个实现的方式:

class SingletonDemo private constructor(private val property: Int) {
//这里参数可以根据实际需求发生改变
    companion object {
        @Volatile private var instance: SingletonDemo? = null
        fun getInstance(property: Int) =
                instance ?: synchronized(this) {
                    instance ?: SingletonDemo(property).also { instance = it }
                }
    }
}

其中关于?:操作符,如果 ?: 左侧表达式非空,就返回其左侧表达式,否则返回右侧表达式。 请注意,当且仅当左侧为空时,才会对右侧表达式求值。

相关文章
|
9天前
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
21 4
|
19天前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
20 3
Android面试题之Java 泛型和Kotlin泛型
|
14天前
|
设计模式 安全 Java
Java中的单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点
Java单例模式确保类仅有一个实例,并提供全局访问点。常见实现包括: - 饿汉式:静态初始化,线程安全。 - 懒汉式:延迟初始化,需同步保证线程安全。 - 双重检查锁定:优化懒汉式,减少同步开销。 - 静态内部类:延迟加载,线程安全。 - 枚举:简洁线程安全,不适用于复杂构造。 - 容器实现:如Spring框架,用于依赖注入。选择依据需求,如延迟加载、线程安全和扩展性。
41 10
|
13天前
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
20 8
|
10天前
|
设计模式 SQL 安全
Java设计模式:单例模式之六种实现方式详解(二)
Java设计模式:单例模式之六种实现方式详解(二)
|
12天前
|
Java
JAVA单例模式-双重检验锁(防止反射、序列化多个)
JAVA单例模式-双重检验锁(防止反射、序列化多个)
16 1
|
13天前
|
设计模式 缓存 安全
java中的设计模式&单例模式
java中的设计模式&单例模式
11 1
|
14天前
|
设计模式 安全 Java
Java单例模式确保类仅有一个实例,提供全局访问点。常见实现包括
【6月更文挑战第23天】Java单例模式确保类仅有一个实例,提供全局访问点。常见实现包括: 1. 饿汉式:静态初始化时创建实例,线程安全。 2. 懒汉式:首次请求时创建,需同步保障线程安全。 3. 双重检查锁定:优化懒汉式,减少同步开销。 4. 静态内部类:延迟加载,线程安全。 5. 枚举:简洁线程安全,但构造受限。 6. 容器实现:如Spring框架,适用于依赖注入。选择依据需求如延迟加载、线程安全等。
18 1
|
16天前
|
设计模式 安全 Java
Java设计模式之单例模式详解
Java设计模式之单例模式详解
|
9天前
|
设计模式 安全 Java
在Java中实现单例模式的正确方法
在Java中实现单例模式的正确方法