Kotlin:伴侣对象和顶级对象之间的差异

时间:2018-04-22 18:25:46

标签: kotlin

在Kotlin中创建常量的一般模式似乎是使用伴随对象。但是,我也可以在文件级别定义一个常量。为什么不那么受欢迎?我错过了什么吗?

使用伴侣对象:

class Example {
    companion object {
        const val CONSTANT = "something"
}

在顶层:

const val CONSTANT = "something"

class Example {
}

4 个答案:

答案 0 :(得分:20)

在Java中,您被迫将所有静态字段和方法声明放在一个类中,而且通常您甚至必须为此目的创建一个类。来到Kotlin,很多用户都习惯于寻找相同的设施,最终过度使用伴侣物品。

Kotlin完全解耦了文件和类的概念。您可以声明任意数量的公共类是同一个文件。您还可以声明私有顶级函数和变量,它们只能被同一文件中的类访问。这是组织密切相关的代码和数据的好方法。

与顶级声明相比,伴随对象的语法非常难以处理。只有当您特别想要将某些public static代码或数据与类相关联并希望您的用户使用该类的名称限定对其的访问权限时,才应使用它们。用例非常罕见,在大多数情况下,顶级声明更自然。

如果您希望将某些private static代码/数据与某个类联系起来,那么您最好使用私有顶级声明。

最后,有时候生成的字节码的关注很重要。如果由于某种原因,您必须使用Kotlin代码生成一个Java类,使得该类具有static成员,则必须使用伴随对象和特殊注释。

答案 1 :(得分:9)

使用差异

定义伴随对象中的字段会限制其可用范围,而不会仅导入该类,这有助于防止数据在意外的位置使用。

在文件中定义使该字段可用于与该字段相同的包中的任何代码。

字节码的差异

const val CONSTANT = "something"

class Example {
}

创建以下内容:

<强> Example.java

public final class Example {}

<强> XKt.java

import kotlin.Metadata;
import org.jetbrains.annotations.NotNull;


public final class XKt {
   public static final String CONSTANT = "something";
}

鉴于:

class Example {
    companion object {
        const val CONSTANT = "something"
    }
}

创建以下内容:

public final class Example {
    public static final String CONSTANT = "something";
    public static final Example.Companion Companion = new Example.Companion((DefaultConstructorMarker) null);

    public static final class Companion {
        private Companion() {}

        public Companion(DefaultConstructorMarker $constructor_marker) {
            this();
        }
    }
}

答案 2 :(得分:4)

我认为这主要取决于你是否希望那个常数成为一个类的一部分。如果你把它放在一个companion对象中,它将被这样访问:

Example.CONSTANT

如果您选择在文件级别上放置一个常量,它将从其他文件导入,并且通常只需CONSTANT即可访问。

有理由将常量放在类中以及将它们置于顶级。

请注意,const关键字只能应用于String类型或基本类型(Int等)(reference)的变量。但是,对于大多数情况,不需要应用关键字。定义常量值,如下所示:

val constantFIS = FileInputStream("path")

答案 3 :(得分:0)

有时您实际上需要将常量放在伴随对象之外。显然,伴随对象中的常量并不像人们想象的那样“那么多”常量。例如:

internal const val MY_FOO = "It's my ${Foo.FOO}";

open class Foo {
    internal companion object {
        const val FOO = "foo";
    }
}

@Kaboom(name=MY_FOO)
open class Bar {}

以上代码未编译。只要一些“常量”是伴随对象的一部分,它们就不是真正的常量。但是当您将 FOO 移出伴随对象时,一切正常。

另一方面,我希望编译器为我完成这项工作,并确定是否可以在功能上将某些 static final 字段转换为常量。为什么我要花时间和精力来决定什么是编译器的字面常量?这是错误的。