Kotlin中的静态方法和变量是什么?

134

我想要将一个类的实例保存到私有/公共静态变量中,但是我不知道如何在 Kotlin 中实现这个功能。

public class Foo {
    private static Foo instance;

    public Foo() {
        if (instance == null) {
            instance = this;
        }
    }
    
    public static Foo get() {
        return instance;
    }
}

7
https://kotlinlang.org/docs/reference/classes.html#companion-objects。但是我认为那看起来很糟糕。你为什么想要使用可变的静态字段(已经是不良实践),并在每次构造Foo实例时修改它?你想要实现什么目标? - JB Nizet
3
如果你想创建一个单例对象,请查看 https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations。 - Miha_x64
4个回答

184

更新:任何人(例如OP)只需要所谓的“单例”,有时称为“服务”(除了Android),应该简单地使用Kotlin内置的功能:

object Foo {
    // Done, this already does what OP needed,
    // because the boilerplate codes (like static field and constructor),
    // are taken care of by Kotlin.
}

(正如Roman在评论区中指出的那样。)

之前的回答;如果你有(或计划拥有)多个static变量,那么请继续阅读:

最接近Java静态字段的东西是伴生对象。您可以在此处找到它们的文档参考:https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects

您的Kotlin代码将类似于以下内容:

class Foo {

    companion object {
        private lateinit var instance: Foo

        fun get(): Foo {
            return instance;
        }
    }

    init {
        if (instance == null) {
            instance = this
        }
    }

}

如果你想让你的字段/方法在Java调用者中被暴露为静态的,你可以使用@JvmStatic注解来实现:
class Foo {

    companion object {
        private lateinit var instance: Foo

        @JvmStatic fun get(): Foo {
            return instance;
        }
    }

    init {
        if (instance == null) {
            instance = this
        }
    }

}

请注意,@JvmStatic 不需要任何导入(因为它是 Kotlin 的内置功能)。

18
如果你将Foo声明为object Foo { ... },那么使用伴生对象(companion object)来声明一个实例字段(instance field)的模板代码就会被Kotlin编译器自动处理掉。 - Roman Elizarov
如果你想在Java中像static final字段一样使用它且不需要getter方法,你可能应该将其标记为@JvmField - artaxerx

71

看起来你想要定义一个单例对象。在 Kotlin 中,它被支持作为一级概念:

object Foo {
  ... 
}

Kotlin会自动处理所有带有静态字段和构造函数的样板代码,您不需要编写任何代码。

在Kotlin代码中,您可以简单地引用此对象的实例为Foo。在Java代码中,您可以将此对象的实例引用为Foo.INSTANCE,因为Kotlin编译器会自动创建相应的静态字段INSTANCE


这是更好的解决方案,但是对于我的用例,我需要一个类,因为它需要能够由Java类加载器创建。 - Caleb Bassham
一个对象在整个项目中都是可访问的,但这会阻碍性能吗? - Arthur Kasparian

20

首先创建一个简单的类,然后创建一个块,接着使用伴生对象关键字。

例如:

class Test{

    companion object{

        fun  getValue(): String{

           return "Test String"

        }
    }
}
你可以使用类名加点号加函数名来调用这个类函数。
例如:
// here you will get the function value
Test.getValue() 

3
您可以为类创建一个伴生对象,如果您想要该字段为静态的,则可以使用注解@JvmStatic。伴生对象可以访问其所伴随的类的私有成员。
以下是示例:
class User {
    private lateinit var name: String

    override fun toString() = name

    companion object {
        @JvmStatic
        val instance by lazy {
            User().apply { name = "jtonic" }
        }
    }
}

class CompanionTest {

    @Test
    fun `test companion object`() {
        User.instance.toString() shouldBe "jtonic"
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接