Константы в Котлине - какой рекомендуемый способ их создания?

Как рекомендуется создавать константы в Котлине? И что такое соглашение об именах? Я не нашел этого в документации.

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

    //2
    const val MY_CONST = "something"

    //3
    val myConst = "something"
}

Или...?

Ответ 1

В Kotlin, если вы хотите создать локальные константы, которые должны использоваться в классе, вы можете создать его, как показано ниже

val MY_CONSTANT = "Constants"

И если вы хотите создать публичную константу в kotlin, как public static final в java, вы можете создать ее, как следует.

companion object{

     const val MY_CONSTANT = "Constants"

}

Ответ 2

Избегайте использования сопутствующих объектов. За капотом создаются методы экземпляра 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

Ответ 3

Значения, известные во время компиляции, могут (и, на мой взгляд, должны) быть отмечены как постоянные.

Соглашения об именах должны следовать за Java и должны быть хорошо видны при использовании из Java-кода (как-то трудно достичь с сопутствующими объектами, но в любом случае).

Собственные объявления констант:

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

Ответ 4

Вам не нужен класс, объект или объект-компаньон для объявления констант в Котлине. Вы можете просто объявить файл, содержащий все константы (например, Constants.kt) и прямо объявить константы внутри файла. Константы известные во время компиляции должны быть помечены const.

Таким образом, в этом случае это должно быть:

const val MY_CONST = "something"

и затем вы можете импортировать константу, используя:

import package_name.MY_CONST

Вы можете ссылаться на эту ссылку

Ответ 5

Прежде всего, соглашение о присвоении имен в 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, в котором будут храниться эти глобальные константы (здесь вы хотите широко использовать свой констант во всем проекте):

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()

Ответ 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

Ответ 7

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

Ответ 8

Что-то, что не упоминается ни в одном из ответов, это накладные расходы на использование companion objects. Как вы можете здесь прочитать, объекты-компаньоны на самом деле являются объектами, и их создание расходует ресурсы. Кроме того, вам может потребоваться пройти через несколько функций getter каждый раз, когда вы используете свою константу. Если вам нужно всего несколько примитивных констант, вам, скорее всего, будет лучше использовать val чтобы получить лучшую производительность и избежать 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));
    }
}

Поэтому старайтесь избегать их.

Ответ 9

локальные константы:

const val NAME = "name"

Глобальные константы:

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

доступ к MyConstants.NAME

Ответ 10

Оформить заказ эту статью. Он дает хороший обзор различных способов хранения ваших констант с соответствующими компрометами производительности.

Ответ 11

Для примитивов и струн:

/** 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

Есть несколько способов определить константы в 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, вы должны использовать const перед val, как показано ниже:

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

Так что это лучший способ создания констант.