对Kotlin的伴侣对象定义感到困惑

时间:2018-05-16 09:02:03

标签: kotlin

当我到达电子书中的伴侣对象部分" Kotlin in action"它说:

" 如果你需要编写一个可以调用的函数 如果没有类实例但需要访问类的内部,则可以将其写为该类中对象声明的成员"

正如我的理解,这意味着伴侣对象的一个​​功能可以访问包含它的类的方法和属性。但是,当我尝试实现这一点时,我无法从其伴随对象'函数访问该类的成员:

class Normal() {

var name: String = "hallo"


companion object {
    fun printName() {
        println(name) // ERROR!!! unresolved reference name
    }
}}

我误解了这个概念吗?

4 个答案:

答案 0 :(得分:4)

默认情况下companion内部的方法是静态的(与Java相比,这也是你在Kotlin中实现静态事物的方式),你无法从静态方法中访问常规变量。

同样发生在这里。

编辑: -

书中的定义令人困惑,伴侣对象不是类实例的一部分。您无法从协同对象访问成员,就像在Java中一样,您无法从静态方法访问成员。但是对于只需要执行某些操作的实用程序类,可以调用静态方法,该方法创建一个新的类实例并执行一些函数。

例如,您可以按@user8320224查看答案,我也在这里引用他的代码,

class Normal {
private var name: String = "hallo"
private fun printName() {
    println(name)
}

companion object {
    fun factoryNormal(): Normal {
        val normal = Normal()
        normal.printName()
        normal.name = "new name"
        normal.printName()
        return normal
    }
}
}

答案 1 :(得分:2)

静态成员可以访问类的内部,例如私有成员

class Normal() {
    private var name: String = "hallo"
    private fun printName() {
        println(name)
    }

companion object {
    fun factoryNormal(): Normal {
        val normal = Normal()
        normal.printName()
        normal.name = "new name"
        normal.printName()
        return normal
    }
}}

答案 2 :(得分:1)

companion object与Java中的public static final class相同。因此,您无法访问 var name

也许这会对你有所帮助:

class Normal() {
    companion object {

        @JvmStatic
        var name: String = "hallo"

        // This annotation will be helpful if you are calling 
        // this from Java, so it goes like Normal.printName();
        @JvmStatic 
        fun printName() {
            println(name)
        }
    }
}

现在你可以在Kotlin中使用它了:

Normal.name = "new name"
Normal.printName()

如果你想在Java中使用它,那么:

Normal.setName("new name");
Normal.printName();

答案 3 :(得分:1)

伴侣对象与Java中的“static”相同。它实际上没有任何类的实例。因此,如果您的printname()方法只是说println("Hello again!"),则可以执行以下操作:

println(Normal().name) // creates a new Normal class and prints "hallo"
Normal.printname() // Does not create a new normal class but just prints "Hello again!"

请注意,我们实际上并没有在第二行创建新的Normal(没有构造函数括号)。 printname()方法可以被认为属于类的定义,而不是示例或该类的实例。

它更像是汽车的手册;它可以参考和讨论汽车的内部结构,但你需要有一辆真正的汽车才能用手册做任何有趣的事情。

如果我们有一个实例,我们可以访问该类实例的内部。所以传入一个类的实例会起作用:

class Normal() {

private var name: String = "hallo"

companion object {
    fun printName(normal : Normal) {
        println(normal.name) // Note that I made the "name" var private
    }
}}

伴侣对象也可以访问伴随对象本身内的任何内容,因此这也有效:

class Normal() {  

companion object {

    private var name: String = "hallo"

    fun printName() {
        println(name) // Note I moved the "name" var into the companion object
    }
}}

你可以将这些结合起来:

class Normal() {  
    private var name: String = "Vilpe89"

    companion object {

        private var greeting: String = "Hello "

        fun printName(normal : Normal) {
            println("$greeting ${normal.name}!")
    }
}}

现在您可以像这样调用上面的代码:

Normal.printname(Normal()) // uses Normal's companion object
                           // method on an instance of Normal, 
                           // and prints "Hello Vilpe89!"

这与如果它们是单独的类会发生什么非常不同:

class Normal() {  
    private var name: String = "Vilpe89"
}

class Greeting() {

    private var greeting: String = "Hello "

    fun printName(normal : Normal) {
        println("$greeting ${normal.name}!") // This won't compile, because
                                             // Greeting can't see normal.name 
                                             // if it's private.
    }
}