迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Java >

在 Kotlin 中创建单例

作者:迹忆客 最近更新:2023/05/11 浏览次数:

设计模式是一组基于手头需求的常见问题的解决方案,这些解决方案可以在试图解决相同问题的其他系统中重复使用。 有不同的设计模式,包括创建型、行为型和结构型设计模式。

创建型设计模式处理如何创建对象,在本教程中将学习如何使用单例模式,这是创建型设计模式的一个示例。

单例模式是一种设计模式,有助于创建一个对象的单个副本并提供一个访问点。

在开发应用程序时,有些情况下我们需要一个对象的单个副本,例如线程池、日志记录、设备驱动程序、注册表设置、缓存等的对象。

具有这些对象的多个副本的程序可能会导致不正确的行为、资源过度使用和不一致的结果。 在本教程中,我们将学习在 Kotlin 中创建单例的不同方法。


使用 Kotlin API 创建单例

Kotlin 提供了一个单例,我们可以开箱即用,无需为其编写任何对象创建代码。 为此,我们必须使用 object 关键字定义我们的单例名称,并且在这个单例中,我们可以添加任何成员变量和函数。

打开 IntelliJ 并选择文件 > 新建 > 项目。 在打开的窗口中,输入项目名称 kotlin-singleton,在 Language 部分选择 Kotlin,在 Build system 部分选择 Intellij。

最后,按创建按钮生成项目。

在 src/main/kotlin 文件夹下创建一个名为 Main.kt 的文件,并将以下代码复制并粘贴到该文件中。

object Singleton{
    fun showMessage(): Singleton {
        return Singleton
    }
}

fun main(){
    println(Singleton.showMessage())
    println(Singleton.showMessage())
}

如上所述,这是 Kotlin 中创建单例的默认方式,并且非常容易实现。 请注意,创建的单例对象是线程安全的,这意味着即使是多线程程序也无法创建可能导致数据不一致的新对象。

在这段代码中,我们创建了一个名为 Singleton 的单例和一个名为 showMessage() 的成员函数。 该函数返回对创建的单例的引用。

运行此代码并注意对成员函数的两次调用返回对同一对象的引用,如下所示。

Singleton@5305068a
Singleton@5305068a

使用 Companion 对象创建单例

将前面的例子注释掉,将下面的代码复制粘贴到Main.kt文件注释后。

class Singleton private constructor(){
    companion object{
        var singleton = Singleton();
        fun getInstance(): Singleton{
            if (singleton == null){
                singleton = Singleton();
            }
            return singleton;
        }
    }
}


fun main(){
    println(Singleton.getInstance());
    println(Singleton.getInstance());
}

前一个例子和这个例子的唯一区别是伴随对象是在一个类中使用的。 Kotlin 中的所有静态变量和函数都放在伴生对象中。

在这段代码中,我们创建了一个名为 getInstance() 的方法,它确保只创建对象的一个副本。 为了确保遵守这一点,我们将 constructor() 设为私有,并确保在创建对象之前检查对象是否存在。

请注意 ,这种方法效果很好,但它不是线程安全的。 如果一个应用程序是多线程的,它可以同时访问 getInstance() 方法,从而导致多个对象,从而导致前面提到的问题。

下一节将展示如何使单例线程安全。

运行此代码并确保输出返回对如下所示的同一对象的引用。

Singleton@1f32e575
Singleton@1f32e575

使用Companion对象创建线程安全的单例

将之前的代码注释掉,将下面的代码复制粘贴到Main.kt文件注释后。

class Singleton private constructor(){
    companion object{

        private var singleton = Singleton();

        @Synchronized
        fun getInstance(): Singleton{
            if (singleton == null){
                singleton = Singleton();
            }
            return singleton
        }
    }
}

请注意,这段代码与前面的代码类似; 唯一的区别是我们在 getInstance() 方法上添加了 @Synchronized 注释。

这种方法在 Java 中称为同步方法。 线程安全是通过锁来实现的。

对象通常有锁,当一个线程到达同步方法时,它独占地获得这个锁,直到它创建完一个对象,这意味着没有其他线程可以访问这个方法。

当另一个线程访问锁时,我们已经有一个对象,线程使用现有线程而不创建新线程。 还有其他方法可以实现同步,比如使用synchronized块,它可以帮助我们同步一段代码而不是整个方法。

请注意 ,同步解决了我们的问题,但在我们的应用程序中引入了性能问题。 同步会导致我们应用程序的性能降低 100 倍,如果我们的应用程序对性能至关重要,我们应该重新考虑使用它。

我们可以使用从惰性初始化转变为急切初始化、双重检查锁定的方法,或者在性能不会影响应用程序的情况下保留它。


使用 Lazy Initializer 创建单例

将之前的代码注释掉,将下面的代码复制粘贴到Main.kt文件注释后。

class Singleton{
    companion object{
        val singleton: Singleton by lazy {
            Singleton();
        }
    }

    fun showMessage(): Singleton {
        return Singleton.singleton
    }
}

fun main(){
    println(Singleton.singleton.showMessage())
    println(Singleton.singleton.showMessage())
}

在这段代码中,我们使用函数 lazy() 创建了一个单例,它使用我们传递给它的参数创建了一个线程安全的 Lazy 实例。 它使用 LazyThreadSafetyMode.SYNCHRONIZED 来确保只有一个锁用于初始化惰性实例。

运行此代码并确保输出返回对如下所示的同一对象的引用。

Singleton@3e3abc88
Singleton@3e3abc88

总结

在本篇文章中,我们学习了在 Kotlin 中创建单例对象的不同方法。 涵盖的方法包括使用 object 关键字、伴生对象和惰性初始化函数。

使用 synchronized 方法,我们还学习了如何在使用伴随对象时确保我们的单例对象是线程安全的。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:https://www.jiyik.com/tm/xwzj/prolan_6335.html

相关文章

如何在 Java 中延迟几秒钟的时间

发布时间:2023/12/17 浏览次数:217 分类:Java

本篇文章主要介绍如何在 Java 中制造程序延迟。本教程介绍了如何在 Java 中制造程序延时,并列举了一些示例代码来了解它。

如何在 Java 中把 Hashmap 转换为 JSON 对象

发布时间:2023/12/17 浏览次数:187 分类:Java

它描述了允许我们将哈希图转换为简单的 JSON 对象的方法。本文介绍了在 Java 中把 Hashmap 转换为 JSON 对象的方法。我们将看到关于创建一个 hashmap,然后将其转换为 JSON 对象的详细例子。

如何在 Java 中按值排序 Map

发布时间:2023/12/17 浏览次数:171 分类:Java

本文介绍了如何在 Java 中按值对 Map 进行排序。本教程介绍了如何在 Java 中按值对 Map 进行排序,并列出了一些示例代码来理解它。

如何在 Java 中打印 HashMap

发布时间:2023/12/17 浏览次数:192 分类:Java

本帖介绍了如何在 Java 中打印 HashMap。本教程介绍了如何在 Java 中打印 HashMap 元素,还列举了一些示例代码来理解这个主题。

在 Java 中更新 Hashmap 的值

发布时间:2023/12/17 浏览次数:146 分类:Java

本文介绍了如何在 Java 中更新 HashMap 中的一个值。本文介绍了如何在 Java 中使用 HashMap 类中包含的两个方法-put() 和 replace() 更新 HashMap 中的值。

Java 中的 hashmap 和 map 之间的区别

发布时间:2023/12/17 浏览次数:79 分类:Java

本文介绍了 Java 中的 hashmap 和 map 接口之间的区别。本教程介绍了 Java 中 Map 和 HashMap 之间的主要区别。在 Java 中,Map 是用于以键值对存储数据的接口,

在 Java 中获取用户主目录

发布时间:2023/12/17 浏览次数:218 分类:Java

这篇文章向你展示了如何在 Java 中获取用户主目录。本教程介绍了如何在 Java 中获取用户主目录,并列出了一些示例代码以指导你完成该主题。

Java 中 size 和 length 的区别

发布时间:2023/12/17 浏览次数:179 分类:Java

这篇文章教你如何知道 Java 中大小和长度之间的区别。本教程介绍了 Java 中大小和长度之间的区别。我们还列出了一些示例代码以帮助你理解该主题。

Java 中的互斥锁

发布时间:2023/12/17 浏览次数:111 分类:Java

了解有关 Java 中互斥锁的一切,在计算机科学领域,互斥或互斥被称为并发控制的属性。每台计算机都使用称为线程的最小程序指令序列。有一次,计算机在一个线程上工作。为了更好地理解,

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便