建议如何在Kotlin中创建常量?命名规则是什么?我在文档里没有找到。

companion object {
    //1
    val MY_CONST = "something"

    //2
    const val MY_CONST = "something"

    //3
    val myConst = "something"
}

或者…?


在编译时已知的值可以(并且在我看来应该)被标记为常量。

命名约定应该遵循Java约定,并且在从Java代码中使用时应该正确可见(这在某种程度上很难通过伴生对象实现,但无论如何)。

正确的常量声明是:

const val MY_CONST = "something"
const val MY_INT = 1

在Kotlin中,如果你想创建在类中使用的局部常数,那么你可以像下面这样创建它

val MY_CONSTANT = "Constants"

如果你想在kotlin中创建一个公共常量,就像在java中创建public static final一样,你可以像下面这样创建它。

companion object{

     const val MY_CONSTANT = "Constants"

}

当地常量:

const val NAME = "name"

全局常量:

object MyConstants{
    val NAME = "name"
    val ID = "_id"
    var EMAIL = "email"
}

访问MyConstants。的名字


class Myclass {

    companion object {
        const val MYCONSTANT = 479
    }
}

你有两个选择,你可以使用const关键字或使用@JvmField,这使它成为java的静态最终常量。

class Myclass {

    companion object {
        @JvmField val MYCONSTANT = 479
    }
}

如果您使用@JvmField注释,那么在它编译之后,常量就会以java中调用它的方式为您放入。 就像你在java中调用它一样,当你在代码中调用同伴常量时,编译器会为你替换它。

但是,如果使用const关键字,则常量的值将内联。内联是指在编译后使用实际值。

所以总结一下编译器将为你做什么:

//so for @JvmField:

Foo var1 = Constants.FOO;

//and for const:

Foo var1 = 479

在Kotlin中声明常量不需要类、对象或伴生对象。您可以声明一个包含所有常量的文件(例如constants。或者你也可以把它们放在任何现有的Kotlin文件中),并直接在文件中声明常量。编译时已知的常量必须用const标记。

所以,在这种情况下,它应该是:

const val MY_CONST = "something"

然后你可以导入常量使用:

import package_name.MY_CONST

你可以参考这个链接


Something that isn't mentioned in any of the answers is the overhead of using companion objects. As you can read here, companion objects are in fact objects and creating them consumes resources. In addition, you may need to go through more than one getter function every time you use your constant. If all that you need is a few primitive constants on a few instances of your class, you'll probably just be better off using val to get a better performance and avoid the companion object. The trade off is higher memory consumption if you have many instances of your class so everyone should make their own decision.

TL,博士;文章:

使用伴侣对象实际上会将以下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));
    }
}

避免使用伴随对象。在底层,为可访问的字段创建了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 valName = valValue放在类名之前,这样就会创建一个

public static final YourClass。Kt会有公共的静态最终值。

科特林:

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

对于基元和字符串:

/** The empty String. */
const val EMPTY_STRING = ""

其他情况:

/** The empty array of Strings. */
@JvmField val EMPTY_STRING_ARRAY = arrayOfNulls<String>(0)

例子:

/*
 * Copyright 2018 Vorlonsoft LLC
 *
 * Licensed under The MIT License (MIT)
 */

package com.vorlonsoft.android.rate

import com.vorlonsoft.android.rate.Constants.Utils.Companion.UTILITY_CLASS_MESSAGE

/**
 * Constants Class - the constants class of the AndroidRate library.
 *
 * @constructor Constants is a utility class and it can't be instantiated.
 * @since       1.1.8
 * @version     1.2.1
 * @author      Alexander Savin
 */
internal class Constants private constructor() {
    /** Constants Class initializer block. */
    init {
        throw UnsupportedOperationException("Constants$UTILITY_CLASS_MESSAGE")
    }

    /**
     * Constants.Date Class - the date constants class of the AndroidRate library.
     *
     * @constructor Constants.Date is a utility class and it can't be instantiated.
     * @since       1.1.8
     * @version     1.2.1
     * @author      Alexander Savin
     */
    internal class Date private constructor() {
        /** Constants.Date Class initializer block. */
        init {
            throw UnsupportedOperationException("Constants.Date$UTILITY_CLASS_MESSAGE")
        }

        /** The singleton contains date constants. */
        companion object {
            /** The time unit representing one year in days. */
            const val YEAR_IN_DAYS = 365.toShort()
        }
    }

    /**
     * Constants.Utils Class - the utils constants class of the AndroidRate library.
     *
     * @constructor Constants.Utils is a utility class and it can't be instantiated.
     * @since       1.1.8
     * @version     1.2.1
     * @author      Alexander Savin
     */
    internal class Utils private constructor() {
        /** Constants.Utils Class initializer block. */
        init {
            throw UnsupportedOperationException("Constants.Utils$UTILITY_CLASS_MESSAGE")
        }

        /** The singleton contains utils constants. */
        companion object {
            /** The empty String. */
            const val EMPTY_STRING = ""
            /** The empty array of Strings. */
            @JvmField val EMPTY_STRING_ARRAY = arrayOfNulls<String>(0)
            /** The part 2 of a utility class unsupported operation exception message. */
            const val UTILITY_CLASS_MESSAGE = " is a utility class and it can't be instantiated!"
        }
    }
}

首先,Kotlin中常量的命名约定与java中相同(例如:MY_CONST_IN_UPPERCASE)。

我应该如何创建它?

1. 作为顶级值(推荐)

你只需要把const放在类声明的外面。

两种可能:在类文件中声明const(你的const与你的类有明确的关系)

private const val CONST_USED_BY_MY_CLASS = 1

class MyClass { 
    // I can use my const in my class body 
}

创建一个专用的常量。在这里你想要在你的项目中广泛使用你的const文件:

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://
    }
}

2. 在伴生对象(或对象声明)中声明它

这就不那么干净了,因为在底层,当字节码生成时,会创建一个无用的对象:

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(编译器将生成一个无用的对象+一个无用的函数):

MyClass {
    companion object {
        val URL_PATH = "https://"
    }
}

注意:

在kotlin中,const只能保存原始类型。如果希望将调用函数的结果分配给它,则需要添加@JvmField注释。在编译时,它将被转换为一个公共静态final变量。但是它比原始类型要慢。尽量避免。

@JvmField val foo = Foo()

在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";
      }
    }

现在,如果您看到上面的反编译代码,它正在为每个变量创建get方法。这个get方法根本不是必需的。

要摆脱这些get方法,你应该在val之前使用const,如下所示:

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;
      }
    }

所以这是创建常数的最好方法。


Kotlin静态和常量值&方法声明

object MyConstant {

@JvmField   // for access in java code 
val PI: Double = 3.14

@JvmStatic // JvmStatic annotation for access in java code
fun sumValue(v1: Int, v2: Int): Int {
    return v1 + v2
}

}

在任何地方访问值

val value = MyConstant.PI
val value = MyConstant.sumValue(10,5)

像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


我认为这将是把一个包的所有常量放在同一个文件中的最好方法,正如在其他答案中提到的,这避免了创建伴侣对象,这使得这个性能和非常类似于Java constants类。

class Constants {
    object Analytics {
        const val PROJECT_OPEN = "project_open"
        const val PROJECT_CLOSE = "project_close"
    }

    object HTTP {
        const val BASE_URL = "x.y.com"
    }

    object DBConst {
        const val TABLE_NAME = "abc"
    }
}

这可以从这样的代码中引用,使其非常结构化。

Constants.Analytics.PROJECT_OPEN
Constants.HTTP.BASE_URL
Constants.DBConst.TABLE_NAME

在Kotlin中,当我们声明变量时,有两个选项。'var'或'val'。 遵循变量的命名惯例,我认为我们可以简单地生成“常量”,这意味着我想要一个固定的值分配给一个特定的变量,就像下面的示例代码。

private val tag = "MainActivity"

我认为我们不需要像在Java世界中所做的那样,麻烦地使用大写字母来区分“常量”和变量。