Я хочу знать, как создать одноэлементный класс в Kotlin, чтобы мой класс Util создавал его экземпляр только один раз за выполнение приложения. Однако, когда я преобразовал свой класс Java в kotlin, был сгенерирован приведенный ниже код.
Это правильно?
companion object {
private var utilProject: UtilProject? = null
val instance: UtilProject
get() {
if (utilProject == null) utilProject = UtilProject()
return utilProject!!
}
}
Я мог найти связанный вопрос, но он с параметрами, и я не могу конвертировать его без параметров.
Только
companion object {
val instance = UtilProject()
}
выполнит свою работу, потому что сопутствующий объект сам по себе является синглтоном на уровне языка.
(instance будет создан при вызове сопутствующего объекта первый.)
- Обновлено -
Если вам нужно контролировать, когда инициализируется одноэлементный объект, вы можете создать по одному объекту для каждого класса.
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's companion object is instantiated.
val c = AnotherClass.instance
}
Здесь AnotherClass.instance инициализируется до фактического вызова AnotherClass.instance. Он инициализируется при вызове сопутствующего объекта 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 используется впервые).
@Khemraj Нет. companion object - это одноэлементный объект. Если вам нужно много разных синглтонов, вы можете создать много объектов для каждого синглтона. Обновлю ответ.
Хорошее объяснение !, Тем не менее мне нужен год, чтобы понять синтаксис этого нового языка.
Это не лучший ответ, потому что лучший способ создать класс утилиты - использовать ключевое слово объекта вместо ключевого слова класса - тогда это синглтон уровня языка, и нам не нужно беспокоиться о создании экземпляра такого класса. . Мы просто используем функции так же, как статические методы Java. Пожалуйста, посмотрите мой ответ
The companion object is one singleton object. If you need many different singletons, you can create many objects for each singleton. - хе-хе, хорошая шутка, братан
А как насчет ИНИЦИАЛИЗАЦИИ синглтона? Если у ojbect не может быть конструктора, следует ли использовать блок инициализатора (init {...})?
В Котлине есть специальное ключевое слово object для синглтонов. Вы можете просто ввести что-то вроде этого, чтобы получить рабочий одноэлементный класс:
object MySingleton
или когда вам нужны некоторые функции-члены:
object MySingleton {
fun someFunction(...) {...}
}
А потом используйте это:
MySingleton.someFunction(...)
есть ссылка: https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations
Обновлено:
В вашем случае вам просто нужно заменить в своем определении 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
Я этого не понял. Чем это может быть полезно для моего класса Util?
против создания companion object, просто измените декларацию class UtilProject на object UtilProject
Нравится ответ @Naetmul?
фактически, использование object вместо class - это ваш синглтон. упомянутая ссылка выше стоит прочитать ;-)
Как мы можем создать одноэлементный (объектный) класс с расширенным базовым классом? Кроме того, базовый класс ожидает некоторого контекста в качестве параметра конструктора? Это возможно?. В моем понимании у объектного класса не будет конструктора.
Насколько я понимаю, вы хотите создать синглтон, который расширяет какой-то другой класс, вы можете просто сделать это, просто сделав это: object MySingleton: BaseClass("some value"), где abstract class BaseClass(val value: String), конечно, ваш BaseClass не должен быть абстрактным.
Использование object вместо class - наиболее оптимизированное решение. Если вы хотите вызвать метод внутри своего объекта из класса JAVA, вы можете использовать Singleton.INSTANCE.methodeName()..
В Kotlin вы должны полностью избавиться от понятия служебного класса singleton. Идиоматический способ - просто переместить все объявления на верхний уровень.
Джава:
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 вы просто создаете файл в собственном пакете.
Требуется только слово «объект».
object UtilProject {
var bar: Int = 0
fun foo() {
}
}
И вы напрямую получаете доступ к объекту, который имеет только один экземпляр
fun main(args: Array<String>) {
UtilProject.bar = 1
println(UtilProject.bar)
}
Пример модернизации 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
}
}
То, как вы реализуете метод getInstance(), неверно. Логика внутри getInstance() говорит, что он всегда будет возвращать значение non-null, но ваш тип возврата (Api?) говорит, что он может возвращать значение null. Если вы попытаетесь преобразовать тип возвращаемого значения в Api, вы получите предупреждение Smart cast to a mutable property is not possible.
Супер простой ленивый пример:
companion object {
val instance: UtilProject by lazy { UtilProject() }
}
не нужно! просто используйте ключевое слово объекта
Истинный. Собственно, ключевое слово object делает то же самое
class TestMySingleton private constructor() {
companion object {
var single = TestMySingleton()
fun getInstance(): TestMySingleton {
if (single == null)
single = TestMySingleton()
return single
}
}
}
class MyClass {
init {
println("init is called")
}
companion object {
private var obj: MyClass? = null
fun getInstance(): MyClass {
if (obj == null) {
obj = MyClass()
}
return obj as MyClass
}
}
fun printHello() {
println("Hello World")
}
Вы можете создать его экземпляр с помощью MyClass.getInstance(), например, java
Это поможет. Я использую класс Dialog, но вы можете использовать этот пример, чтобы понять, как его реализовать.
class MyClass(context: Context) : Dialog(context) {
companion object {
lateinit var INSTANCE: MyClass
@JvmStatic
fun getInstance(context: Context): MyClass{
if (!::INSTANCE.isInitialized) {
INSTANCE = MyClass(context)
}
return INSTANCE
}
}}
Вариант с параметрами
open class SingletonHolder<out T: Any, in A>(creator: (A) -> T) {
private var creator: ((A) -> T)? = creator
@Volatile private var instance: T? = null
fun getInstance(arg: A): T {
val checkInstance = instance
if (checkInstance != null) {
return checkInstance
}
return synchronized(this) {
val checkInstanceAgain = instance
if (checkInstanceAgain != null) {
checkInstanceAgain
} else {
val created = creator!!(arg)
instance = created
creator = null
created
}
}
}
}
Отличный ответ, но это только часть всего. Этот код скопирован отсюда: blog.mindorks.com/how-to-create-a-singleton-class-in-kotlin Взгляните, чтобы получить полную картину и почему это способ справиться с этим.
Все ли объекты внутри
companionсинглтон?