Kotlin中的常数 - 建议创建它们的方法是什么?

时间:2017-05-18 04:42:01

标签: android kotlin constants

如何在Kotlin中创建常量?什么是命名惯例?我没有在文档中找到它。

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

    //2
    const val MY_CONST = "something"

    //3
    val myConst = "something"
}

或......?

13 个答案:

答案 0 :(得分:72)

在Kotlin中,如果你想创建应该在课堂上使用的局部常量,那么你可以像下面那样创建它

val MY_CONSTANT = "Constants"

如果你想在kotlin中创建一个公共常量,比如java中的 public static final ,你可以按照以下步骤创建它。

companion object{

     const val MY_CONSTANT = "Constants"

}

答案 1 :(得分:41)

避免使用伴侣对象。在引擎盖后面,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

答案 2 :(得分:16)

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

命名约定应遵循Java约定,并且在从Java代码中使用时应该是正确可见的(使用伴随对象很难实现它,但无论如何)。

正确的常量声明是:

<p style="word-wrap: break-word;">{aVeryLongLine}</p>

答案 3 :(得分:14)

在Kotlin中声明常量时,不需要类,对象或伴随对象。您可以声明一个包含所有常量的文件(例如 Constants.kt )并直接声明文件中的常量。编译时已知的常量必须标有const

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

const val MY_CONST = "something"

然后你可以使用:

导入常量

import package_name.MY_CONST

您可以参考此link

答案 4 :(得分:7)

首先,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 
}

创建一个专用的constants.kt文件,用于存储这些全局const(在这里您想在整个项目中广泛使用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批注。在编译时,它将被转换为公共静态最终变量。但这比原始类型要慢。尝试避免它。

@JvmField val foo = Foo()

答案 5 :(得分:6)

如果您将const val valName = valValue放在班级名称之前,则它将创建一个

public static final YourClass.Kt将具有public static final值。

科特林

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

答案 6 :(得分:6)

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)

答案 7 :(得分:5)

val一样,用const关键字定义的变量是不可变的。这里的区别在于const用于编译时已知的变量。

声明变量const就像在Java中使用static关键字一样。

让我们看看如何在Kotlin中声明一个const变量:

const val COMMUNITY_NAME = "wiki"

用Java编写的类似代码将是:

final static String COMMUNITY_NAME = "wiki";

添加到以上答案-

@JvmField用于指示Kotlin编译器不生成 该属性的获取器/设置器,并将其公开为字段。

 @JvmField
 val COMMUNITY_NAME: "Wiki"

静态字段

在命名对象或伴随对象中声明的Kotlin属性 该命名对象或 包含伴随对象的类。

通常这些字段是私有的,但是可以通过以下方式之一公开它们:

  • @JvmField注释;
  • lateinit修饰符;
  • const修饰符。

此处有更多详细信息-https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields

答案 8 :(得分:2)

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

答案 9 :(得分:2)

任何答案中未提及的是使用companion objects的开销。正如您可以阅读here,伴侣对象实际上是对象,创建它们会消耗资源。此外,每次使用常量时,您可能需要经历多个getter函数。如果您需要的只是一些原始常数,那么您最好使用val来获得better performance并避免使用companion object

TL; DR;文章:

使用随播对象实际上会转换此代码

class MyClass {

    companion object {
        private val TAG = "TAG"
    }

    fun helloWorld() {
        println(TAG)
    }
}

进入此代码:

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

所以尽量避免它们。

答案 10 :(得分:1)

本地常量:

const val NAME = "name"

全局常量:

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

访问MyConstants.NAME

答案 11 :(得分:0)

对于基元和字符串:

/** 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!"
        }
    }
}

答案 12 :(得分:0)

有几种方法可以在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方法。

要摆脱这些获取方法,您应在 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;
      }
    }

因此,这是创建常量的最佳方法。