繁体   English   中英

Kotlin 中 object / 私有构造函数 / 伴侣 object 之间的区别?

[英]Difference between object / private constructor / companion object in Kotlin?

请不要怪我。 我刚刚从 Java 移动到 Kotlin。 I'm trying to create a singleton as a regular java way with help of Singleton.getInstance().someMethod() and have found that in Kotlin there are several different things you can use:

Object(单独文件) object Singleton

配套 object companion object Factory {}

私有构造函数class Singleton private constructor()

所以你能帮我解释一下我们可以在哪里你是什么类型的吗?

object Singleton

  1. 线程安全 singleton
  2. 不是表达式
  3. 不能用于赋值语句的右侧。
  4. Object 声明的初始化是线程安全的,并在第一次访问时完成
  5. 可以有超类型
  6. Object 声明不能是本地的(即直接嵌套在函数内)
  7. 可以嵌套到其他 object 声明或非内部类中

companion object Factory {}

  1. 伴侣 object 的成员可以通过简单地使用 class 名称(托管伴侣)作为限定符来调用
  2. 伴侣object的名称可以省略
  3. 伴随对象的成员看起来像其他语言中的 static 成员,在运行时它们仍然是真实对象的实例成员
  4. 当相应的 class 被加载(已解决)时,伴随的 object 被初始化,匹配 Java ZA8224DF1initializer 的语义

class Singleton private constructor()

I don't think you need that for singleton in kotlin as kotlin already provides good singleton option out of the box, however as stated by other SO user here private constructor is serving the same purpose in kotlin as in, for example, java - to防止实例化。 再想一想,如果您想在 kotlin 中创建类似类的实用程序,请更好地考虑使用扩展函数。

PS.:这应该很明显,所以我会提到它 - 以上内容的 99% 是从https://kotlinlang.org/docs/reference/object-declarations.html残酷地复制粘贴的 - 也许它有更好的机会在这里更容易搜索:)

If you need a singleton - a class that only has got one instance - you can declare the class in the usual way, but use the object keyword instead of class. 如果您需要 function 或要绑定到 class 而不是它的实例的属性(类似于 Python 中的@staticmethod),您可以在伴随的 ZA8CFDE6331BD59EB2AC96F8911C4B66Z.

当没有实例字段或方法(例如 Math class)或调用方法来获取 class 的实例时,私有构造函数用于防止创建 class 的实例。

Kotlin 中的对象类似于 Java 中的 static 类。 它们通常用于构造 singleton 模式:

object Singleton

Java 中的等效项为:

public static class Singleton{}

companion object用于必须应用工厂模式或 static 工厂模式的情况(如您的伴侣 object 名称所述)。

假设我们在 Java 中有这个:

public class Fragment(){
  private Fragment(){}

  public static Fragment newInstance(){
    return new Fragment();
  }
  
}

Kotlin 中的等价物是:

class Fragment private constructor(){
  companion object{
    fun newInstance() = Fragment()
  }
}

The companion object is also an object but through the word companion is just telling JVM that the one class in which this object is, has access to everything inside it.

因此,如果您尝试从 Java 代码中调用它,它将是这样的:

Fragment.Companion.newInstance()

上面的例子实际上也适用于私有构造函数。 基本上,即使在 Java 中,当您不需要直接访问构造函数时,只需将构造函数标记为私有并使用 static 工厂方法即可。

关于您的问题,根据上面提供的信息:

达到

Singleton.getInstance().someMethod()

正是这个电话,你必须这样做:

class Singleton private constructor(){
  companion object{
    fun getInstance() = Singleton()
    fun someMethod(){ /* Your implement here */}
  }
}

然而,这在 Kotlin 风格中并不太复杂。

做就是了:

object Singleton{
    fun someMethod(){ /* Your method here */}
}

然后调用它:

Singleton.myMethod()

编辑:关于您的SharedPreferences问题,我不建议为此使用object 您需要上下文的构造函数,也许还需要共享首选项模式。 因此我会 go 像这样(假设你使用匕首,因为你在评论中提到它):

class SharedPreferencesHelper @Inject constructor(val context: Context, val mode: Int) // not sure about the mode type but check the docs {

    private lateinit var sharedPreferences: SharedPreferences
    private lateinit var sharedPreferencesEditor: SharedPreferences.Editor

    init{
        sharedPreferences = context.getSharedPreferences("filename", mode)
        sharedPreferencesEditor = sharedPreferences.edit()
    }
    
}

然后你只需在你需要的任何构造函数中调用它。

或者:

class SharedPreferencesHelper private constructor(){
    private lateinit var sharedPreferences: SharedPreferences
    private lateinit var sharedPreferencesEditor: SharedPreferences.Editor
    
    companion object {
        fun startSharedPrefs(context: Context, fileName: String, mode: Int) = SharedPreferencesHelper().apply{
         sharedPreferences = context.getSharedPreferences(fileName, mode)
         sharedPreferencesEditor = sharedPreferences.edit()
        }
    }

}

然后在匕首模块中启动它:

@Module
object SharedPrefsModule{
    @Singleton
    @Provides
    fun provideSharedPreferences(application: Application) = 
     SharedPreferencesHelper.startSharedPrefs(application, "fileName", MODE_PRIVATE)

}

然后在需要的地方调用依赖项

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM