如何在 Kotlin 中创建常量并使用什么命名规范?我在文档中没有找到相关内容。
companion object {
//1
val MY_CONST = "something"
//2
const val MY_CONST = "something"
//3
val myConst = "something"
}
还是……呢?
避免使用伴生对象。在底层,会为可访问的字段创建getter和setter实例方法。调用实例方法在技术上比调用静态方法更昂贵。
public class DbConstants {
companion object {
val TABLE_USER_ATTRIBUTE_EMPID = "_id"
val TABLE_USER_ATTRIBUTE_DATA = "data"
}
请将常量定义在 object
中。
推荐做法:
object DbConstants {
const val TABLE_USER_ATTRIBUTE_EMPID = "_id"
const val TABLE_USER_ATTRIBUTE_DATA = "data"
}
您可以像这样全局访问它们:
DbConstants.TABLE_USER_ATTRIBUTE_EMPID
const val
,则声明一个companion object
是正确的。 - Ari Lacenskiconst val
。 - EpicPandaForceval MY_CONSTANT = "Constants"
如果你想在Kotlin中创建一个像Java中的public static final这样的公共常量,你可以按以下方式创建:
companion object {
const val MY_CONSTANT = "Constants"
}
companion object
。我认为@piotrpo的答案应该被采纳。 - ChiaraMY_CONSTANT
实际上不是一个好主意 - 编译器会通过消息 “私有属性名'MY_CONSTANT'不应包含中间或结尾的下划线” 进行警告。这违反了推荐的命名规范。 - Daniel伴生对象(companion object)
和const val
来定义常量是最佳实践。 - Daniel首先,Kotlin中常量的命名规则与Java相同(例如:MY_CONST_IN_UPPERCASE)。
您只需将常量放在类声明之外即可。
两种可能性:在您的类文件中声明常量(您的常量与您的类具有明显的关系)
private const val CONST_USED_BY_MY_CLASS = 1
class MyClass {
// I can use my const in my class body
}
创建一个专用的constants.kt文件,用于存储全局常量(在项目中广泛使用您的常量):
package com.project.constants
const val URL_PATH = "https:/"
然后您只需在需要它的地方导入它:
import com.project.constants
MyClass {
private fun foo() {
val url = URL_PATH
System.out.print(url) // https://
}
}
这样做会生成一个无用的对象,因此这种方法不够优雅:
MyClass {
companion object {
private const val URL_PATH = "https://"
const val PUBLIC_URL_PATH = "https://public" // Accessible in other project files via MyClass.PUBLIC_URL_PATH
}
}
如果你将其声明为val而不是const(编译器将生成一个无用的对象+一个无用的函数),情况会更糟:
更糟的情况是,如果你将其声明为val而不是const(编译器将生成一个无用的对象 + 一个无用的函数):
MyClass {
companion object {
val URL_PATH = "https://"
}
}
Kotlin中的const只能保存原始类型。如果要将其赋值为调用函数的结果,则需要添加@JvmField注释。在编译时,它将被转换为公共静态常量变量。但是与基本类型相比速度较慢。请尽量避免使用。
@JvmField val foo = Foo()
private const val CONST_USED_BY_MY_CLASS = 1
操作时,Android Studio 4.1.1 开始在项目树中将我添加此行的 *.kt 文件显示为“未解决”。这对编译没有任何影响,但一旦我注意到它,就变得非常烦人。希望很快能够修复。 - artman在编译时已知的值可以(而且我认为应该)标记为常量。
命名规范应该遵循Java的规定,并且在从Java代码中使用时应该正确可见(尽管使用伴生对象有些困难,但无论如何)。
适当的常量声明如下:
const val MY_CONST = "something"
const val MY_INT = 1
在 Kotlin 中声明常量时,您不需要使用类、对象或伴生对象。您可以只声明一个包含所有常量的文件(例如 Constants.kt),或者将它们放在任何现有的 Kotlin 文件中。直接在文件内部声明常量即可。在编译时已知的常量必须标记为 const
。
因此,在这种情况下,应该是:
const val MY_CONST = "something"
然后你可以使用以下代码导入常量:
import package_name.MY_CONST
你可以参考这个链接
如果你把const val valName = valValue
放在类名前面,它将创建一个public static final YourClass.Kt
,它会有 public static final
的值。
Kotlin:
const val MY_CONST0 = 0
const val MY_CONST1 = 1
data class MyClass(var some: String)
Java反编译:
public final class MyClassKt {
public static final int MY_CONST0 = 0;
public static final int MY_CONST1 = 1;
}
// rest of MyClass.java
像val
一样,使用const
关键字定义的变量是不可变的。这里的区别在于const
用于在编译时已知的变量。
声明一个const
变量就像在Java中使用static
关键字一样。
让我们看看如何在Kotlin中声明一个const变量:
const val COMMUNITY_NAME = "wiki"
Java中编写的类似代码如下:
final static String COMMUNITY_NAME = "wiki";
在上面的回答中补充一点:
@JvmField
可以用来指示 Kotlin 编译器不为此属性生成 getter/setter 并将其公开为字段。
@JvmField
val COMMUNITY_NAME = "Wiki"
静态字段
Kotlin属性在命名对象或伴生对象中声明时,将具有静态支持字段,这些字段可以在命名对象或包含伴生对象的类中。
通常这些字段是私有的,但可以通过以下方式之一公开:
@JvmField
注释;lateinit
修饰符;const
修饰符。更多详情请参见https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields
本地常量:
const val NAME = "name"
全局常量:
object MyConstants{
val NAME = "name"
val ID = "_id"
var EMAIL = "email"
}
访问MyConstants.NAME
object
是肯定的。它可以清理导入 - 如果将其放在伴生对象中,则人们必须导入MyConstants.Companion.NAME
。此外,您还需要将构造函数标记为私有。这是为了避免使用方便的语言特性而进行的大量工作。 - Hakanai您可以通过几种方式在 Kotlin 中定义常量:
使用伴生对象
companion object {
const val ITEM1 = "item1"
const val ITEM2 = "item2"
}
ClassName.Companion Companion = ClassName.Companion.$$INSTANCE;
@NotNull
String ITEM1 = "item1";
@NotNull
String ITEM2 = "item2";
public static final class Companion {
@NotNull
private static final String ITEM1 = "item1";
@NotNull
public static final String ITEM2 = "item2";
// $FF: synthetic field
static final ClassName.Companion $$INSTANCE;
private Companion() {
}
static {
ClassName.Companion var0 = new ClassName.Companion();
$$INSTANCE = var0;
}
}
从这里你可以轻松地看到文档的内容,尽管伴生对象的成员看起来像其他语言中的静态成员,但在运行时它们仍然是真实对象的实例成员。 这做了比所需更多的工作。
现在另一种方法出现了,我们不需要使用伴生对象,像下面这样:
object ApiConstants {
val ITEM1: String = "item1"
}
如果你查看上述代码的反编译版本的字节码,你会发现类似这样的内容:
public final class ApiConstants {
private static final String ITEM1 = "item1";
public static final ApiConstants INSTANCE;
public final String getITEM1() {
return ITEM1;
}
private ApiConstants() {
}
static {
ApiConstants var0 = new ApiConstants();
INSTANCE = var0;
CONNECT_TIMEOUT = "item1";
}
}
object ApiConstants {
const val ITEM1: String = "item1"
}
public final class ApiConstants {
public static final String ITEM1 = "item1";
public static final ApiConstants INSTANCE;
private ApiConstants() {
}
static {
ApiConstants var0 = new ApiConstants();
INSTANCE = var0;
}
}
这是创建常量的最佳方式。
CONNECT_TIMEOUT
从哪里来的? - izogfif在任何答案中都没有提到的问题是使用 companion objects
的开销。正如您可以在 这里 阅读到的那样,伴生对象实际上是对象,创建它们需要消耗资源。此外,每次使用常量时,您可能需要经过多个 getter 函数。如果您所需的仅是类的几个实例上的一些原始常量,则最好使用 val
来获得 更好的性能 并避免使用 companion object
。这种权衡是如果您有许多类实例,则会导致更高的内存消耗,因此每个人都应该自行决定。
文章的 TL;DR;:
实际上将此 Kotlin 代码使用伴生对象:
class MyClass {
companion object {
private val TAG = "TAG"
}
fun helloWorld() {
println(TAG)
}
}
转化为这段 Java 代码:
public final class MyClass {
private static final String TAG = "TAG";
public static final Companion companion = new Companion();
// synthetic
public static final String access$getTAG$cp() {
return TAG;
}
public static final class Companion {
private final String getTAG() {
return MyClass.access$getTAG$cp();
}
// synthetic
public static final String access$getTAG$p(Companion c) {
return c.getTAG();
}
}
public final void helloWorld() {
System.out.println(Companion.access$getTAG$p(companion));
}
}
public static final
字段的东西,在你的伴生对象中使用const val
。如果你想要一个private static final
字段和一个公共getter,就在你的伴生对象中使用val
。 - Michael