在java中,我们可以使用双重Checked Locking& amp;编写thead-safe单例。易失性:
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance(String arg) {
Singleton localInstance = instance;
if (localInstance == null) {
synchronized (Singleton.class) {
localInstance = instance;
if (localInstance == null) {
instance = localInstance = new Singleton(arg);
}
}
}
return localInstance;
}
}
我们如何在kotlin中写出来?
object A {
object B {}
object C {}
init {
C.hashCode()
}
}
我用kotlin反编译器来获取
public final class A {
public static final A INSTANCE;
private A() {
INSTANCE = (A)this;
A.C.INSTANCE.hashCode();
}
static {
new A();
}
public static final class B {
public static final A.B INSTANCE;
private B() {
INSTANCE = (A.B)this;
}
static {
new A.B();
}
}
public static final class C {
public static final A.C INSTANCE;
private C() {
INSTANCE = (A.C)this;
}
static {
new A.C();
}
}
}
所有对象都在static
块中调用构造函数。基于此,我们可以认为它不是懒惰的。
class Singleton {
companion object {
val instance: Singleton by lazy(LazyThreadSafetyMode.PUBLICATION) { Singleton() }
}
}
反编译:
public static final class Companion {
// $FF: synthetic field
private static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Singleton.Companion.class), "instance", "getInstance()Lru/example/project/tech/Singleton;"))};
@NotNull
public final Singleton getInstance() {
Lazy var1 = Singleton.instance$delegate;
KProperty var3 = $$delegatedProperties[0];
return (Singleton)var1.getValue();
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
我希望Kotlin开发人员将来能够实现非反思......
答案 0 :(得分:23)
Kotlin具有相当于您的Java代码,但更安全。即使是Java ,也不建议使用<{3}} 。在Java中,您应该使用double lock check,inner class on the static中也会对此进行解释。
但那是Java。 在Kotlin中,只需使用一个对象(一个可选的懒惰委托):
object Singletons {
val something: OfMyType by lazy() { ... }
val somethingLazyButLessSo: OtherType = OtherType()
val moreLazies: FancyType by lazy() { ... }
}
然后,您可以访问任何成员变量:
// Singletons is lazy instantiated now, then something is lazy instantiated after.
val thing = Singletons.something // This is Doubly Lazy!
// this one is already loaded due to previous line
val eager = Singletons.somethingLazyButLessSo
// and Singletons.moreLazies isn't loaded yet until first access...
Kotlin有意避免人们对Java中单身人士的困惑。并避免错误的版本&#34;这种模式 - 其中有很多。相反,它提供了更简单,最安全的单身形式。
考虑到使用lazy()
,如果你有其他成员,每个人都会懒得。因为它们是在传递给lazy()
的lambda中初始化的,所以你可以做一些关于自定义构造函数和每个成员属性的问题。
因此,您延迟加载Singletons
对象(首次访问实例),然后加载something
(首次访问时成员),以及对象构建的完全灵活性。
另见:
作为附注,查看Kotlin的对象注册表类型库,它们与依赖注入类似,为您提供带注入选项的单例:
答案 1 :(得分:14)
Object declaration正是出于此目的:
object Singleton {
//singleton members
}
它是懒惰且线程安全的,它在第一次调用时初始化,就像Java的静态初始化器一样。
您可以在顶级或类或其他对象内声明object
。
有关使用Java的object
的更多信息,请参阅this answer。
<小时/> 至于参数,如果你想要实现完全相同的语义(第一次调用
getInstance
采用其参数初始化单例,后面的调用只返回实例,删除参数),我建议这个结构:< p>
private object SingletonInit { //invisible outside the file
lateinit var arg0: String
}
object Singleton {
val arg0: String = SingletonInit.arg0
}
fun Singleton(arg0: String): Singleton { //mimic a constructor, if you want
synchronized(SingletonInit) {
SingletonInit.arg0 = arg0
return Singleton
}
}
此解决方案的主要缺陷是,它需要在单独的文件中定义单例以隐藏object SingletonInit
,并且在初始化之前不能直接引用Singleton
。 / p>
另外,请参阅a similar question有关为单身人士提供参数的信息。
答案 2 :(得分:4)
我最近写了an article on that topic。 TL; DR这是我提出的解决方案:
1)创建一个SingletonHolder
类。你只需要写一次:
open class SingletonHolder<out T, in A>(creator: (A) -> T) {
private var creator: ((A) -> T)? = creator
@Volatile private var instance: T? = null
fun getInstance(arg: A): T {
val i = instance
if (i != null) {
return i
}
return synchronized(this) {
val i2 = instance
if (i2 != null) {
i2
} else {
val created = creator!!(arg)
instance = created
creator = null
created
}
}
}
}
2)在你的单身人士中使用它:
class MySingleton private constructor(arg: ArgumentType) {
init {
// Init using argument
}
companion object : SingletonHolder<MySingleton, ArgumentType>(::MySingleton)
}
单例初始化将是惰性和线程安全的。