Singleton класс в Котлине

Я хочу знать способ создания singleton-класса, так что мой класс Util создается только один раз для каждого приложения. Однако, когда я преобразовал свой Java-класс в kotlin, под кодом был создан.

Это правильно?

companion object {
    private var utilProject: UtilProject? = null

    val instance: UtilProject
        get() {
            if (utilProject == null) utilProject = UtilProject()
            return utilProject!!
        }
} 

Я мог бы найти связанный с этим вопрос, но это параметр, и я не получаю его без параметров.

Ответы

Ответ 1

Просто

companion object {
    val instance = UtilProject()
} 

будет выполнять эту работу, потому что сам объект-компаньон является одноэлементным языком.
(instance будет назначен при первом вызове сопутствующего объекта.)

- Обновлено -

Если вам нужно настроить, когда объект singleton должен быть инициализирован, вы можете создать один объект для каждого класса.

class UtilProject {
    ....
    companion object {
        val instance = UtilProject()
    }
}

class AnotherClass {
    ...
    companion object {
        val instance = AnotherClass()
        const val abc = "ABC"
    }
}

fun main(args: Array<String>) {
    val a = UtilProject.instance // UtilProject.instance will be initialized here.
    val b = AnotherClass.abc // AnotherClass.instance will be initialized here because AnotherClass companion object is instantiated.
    val c = AnotherClass.instance
}

Здесь AnotherClass.instance инициализируется до AnotherClass.instance как на самом деле AnotherClass.instance. Он инициализируется при AnotherClass сопутствующего объекта AnotherClass. Чтобы предотвратить инициализацию до того, когда это необходимо, вы можете использовать следующее:

class UtilProject {
    ....
    companion object {
        fun f() = ...
    }
}

class AnotherClass {
    ...
    companion object {
        const val abc = "ABC"
    }
}

object UtilProjectSingleton {
    val instance = UtilProject()
}

object AnotherClassSingleton {
    val instance = AnotherClass()
}

fun main(args: Array<String>) {
    UtilProject.f()
    println(AnotherClass.abc)

    val a = UtilProjectSingleton.instance // UtilProjectSingleton.instance will be initialized here.
    val b = AnotherClassSingleton.instance // AnotherClassSingleton.instance will be initialized here.

    val c = UtilProjectSingleton.instance // c is a.
}

Если вам не все равно, когда каждый синглтон инициализирован, вы также можете использовать:

class UtilProject {
    ....
    companion object {
        fun f() = ...
    }
}

class AnotherClass {
    ...
    companion object {
        const val abc = "ABC"
    }
}

object Singletons {
    val utilProject = UtilProject()
    val anotherClass = AnotherClass()
}

fun main(args: Array<String>) {
    val a = Singletons.utilProject
    val b = Singletons.anotherClass 
}

В итоге,
object или companion object является одним одноэлементным объектом в Котлине.
Вы можете назначать переменные в объекте или объектах, а затем использовать переменные так же, как они были одиночными.

object или companion object создается при его первом использовании. val и var в object инициализируются при первом экземпляре object (т.е. когда object сначала используется).

Ответ 2

В Kotlin есть специальное ключевое слово object для синглетонов. Вы можете просто напечатать что-нибудь простое, чтобы получить рабочий одноэлементный класс:

object MySingleton

или когда вам нужны некоторые функции-члены:

object MySingleton {
    fun someFunction(...) {...}
}

А затем используйте его:

MySingleton.someFunction(...)

есть ссылка: https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations

EDIT:

В вашем случае вам просто нужно заменить в своем определении class UtilProject следующее:

object UtilProject {

    // here you put all member functions, values and variables
    // that you need in your singleton Util class, for example:

    val maxValue: Int = 100

    fun compareInts(a: Int, b: Int): Int {...}
}

И тогда вы можете просто использовать свой синглтон в других местах:

UtilProject.compareInts(1, 2)
//or
var value = UtilProject.maxValue

Ответ 3

Супер простой ленивый пример:

companion object {
    val instance: UtilProject by lazy { UtilProject() }
}

Ответ 4

В Kotlin вы должны избавиться от всего понятия утилиты синглтон-класса. Идиоматический способ - просто переместить все объявления на верхний уровень.

Джава:

public final class Util {
    public static final Util UTIL = new Util();

    private int prefixLength = 4;

    private Util() {}

    public void setPrefixLength(int newLen) {
        prefixLength = newLen;
    }

    public String extractVin(String input) {
        return input.substring(prefixLength);
    }
}

Использование:

String vin = UTIL.extractVin("aoeuVN14134230430")

В Kotlin просто создайте отдельный файл с именем util.kt со следующим:

var prefixLength = 4

fun String.extractVin() = this.substring(prefixLength)

Использование:

val vin = "aoeuVN14134230430".extractVin()

Но... вы загрязняете пространство имен верхнего уровня!

Если ваша интуиция Java вызывает здесь красный флаг, просто помните, что пакет является конструкцией пространства имен, и в отличие от Java, Kotlin не разделяет проблемы пространства имен и инкапсуляции. Нет никакого уровня доступа "пакетный приватный", так что вы освобождаетесь от необходимости решать, что что-то должно оставаться в одном пакете, чтобы его можно было сделать пакетным.

Итак, если в Java вы создаете вырожденный класс в качестве обходного пути, в Kotlin вы просто создаете файл в своем собственном пакете.

Ответ 5

Требуется только объект слова.

object UtilProject {
    var bar: Int = 0
    fun foo() {        
    }
}

И вы напрямую обращаетесь к объекту, который имеет только один экземпляр

fun main(args: Array<String>) {
    UtilProject.bar = 1
    println(UtilProject.bar)    
}

Ответ 6

Пример Singleton по модернизации для поддержки вызова API.

object RetrofitClient {

    private var instance: Api? = null
    private val BASE_URL = "https://jsonplaceholder.typicode.com/"

    fun getInstance(): Api? {
        if (instance == null) {
            val retrofit = Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
            instance = retrofit.create(Api::class.java)
        }
        return instance
    }
}