Kotlinの定数—それらを作成するための推奨される方法は何ですか?


165

Kotlinで定数を作成することはどのように推奨されますか?そして、命名規則は何ですか?ドキュメントではそれが見つかりません。

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

    //2
    const val MY_CONST = "something"

    //3
    val myConst = "something"
}

または...?


4
public static finalJavaのフィールドに対応するものが必要な場合const valは、コンパニオンオブジェクトで使用します。あなたがしたい場合はprivate static final、フィールドや公共ゲッターを使用しval、あなたのコンパニオンオブジェクトに。
マイケル

2
Kotlinで定数を定義する方法を説明するブログ投稿は次のとおりです。blog.egorand.me/ where
do

この記事をチェックしてください。これは、定数を保存するさまざまな方法の概要と、関連するパフォーマンスのトレードオフを示しています。
ファイアドリルサージェント2018

回答:


132

Kotlinで、クラスで使用されることになっているローカル定数を作成したい場合は、以下のように作成できます

val MY_CONSTANT = "Constants"

そして、Javaのpublic static finalのようにkotlinでpublic定数を作成する場合は、次のように作成できます。

companion object{

     const val MY_CONSTANT = "Constants"

}

3
名前の付いた新しいファイルなどの別のファイルでどのように使用しますConstants.ktか?
Naveed Abbas

2
定数用のファイルを使用します。すべての定数をそこに保持します。
filthy_wizard

2
あなたは必要ありませんcompanion object。@ piotrpoの回答は受け入れられるべきだと思います
Chiara

@Chiaraコンパニオンオブジェクト(およびそれを含むクラス)は、トップレベルの宣言ではなく、名前空間として機能します。どちらの答えも状況によっては意味があると思います。
jingx 2018

@jingxはい、名前空間を追加する必要があります。:+1:
キアラ

118

コンパニオンオブジェクトの使用は避けてください。内部では、フィールドにアクセスできるように、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コンパニオンオブジェクトでは、より任意の異なる場合がconst val通常のオブジェクトで(あなたの例の間、すなわち唯一の違いは、省略することをあるように思わconstコンパニオンオブジェクトの場合には-あなたが追加した場合const、例は、同じ性能を持つ必要があります)
アーウィンボルウィット

1
@ErwinBolwidt @sudeshのポイントは、構造体の唯一の目的がいくつかの定数値の名前空間を提供することである場合は、クラスラッピングコンパニオンオブジェクトのデザインを使用してはならないということです。ただし、構造をインスタンス化可能にする必要があり、2つ以上のを囲む必要がある場合はconst val、aを宣言するのcompanion objectが適切です。
Ari Lacenski

7
@ErwinBolwidt:sudeshは正しい、コンパニオンオブジェクト用に生成されたバイトコードには、内部でゲッターを使用した追加のオブジェクト作成が含まれます。逆コンパイルされたkotlinの例の適切な説明については、blog.egorand.me / where
ドミニク

2
おかげで@dominik、これは非常に詳細な記事で、私は徹底的にこれを理解したいすべての人にこれをお勧めし、kotlinは次善のバイトコードを生成し、多くの例があり、ジェットブレーンズは、多くのそのようなパフォーマンス関連のバグを解決した...に目を離さない議論.kotlinlang.orgでは、そのような多くの基本的な側面について通知されます。
sudesh

1
今日、あなたの答えから多くを学びました@sudeshありがとう!
ラキダベール

34

まず、定数のKotlinの命名規則は、Javaの場合と同じです(例:MY_CONST_IN_UPPERCASE)。

どうすれば作成できますか?

1.トップレベルの値として(推奨)

const をクラス宣言のに置くだけです。

2つの可能性:クラスファイルでconstを宣言します(constはクラスと明確な関係があります)

private const val CONST_USED_BY_MY_CLASS = 1

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

これらのグローバルconstを保存する専用のconstants.ktファイルを作成します(ここでは、プロジェクト全体で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
    }
}

constの代わりにvalとして宣言するとさらに悪い(コンパイラーは役に立たないオブジェクト+役に立たない関数を生成します):

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

注意 :

kotlinでは、constはプリミティブ型のみを保持できます。関数を渡したい場合は、@ JvmFieldアノテーションを追加する必要があります。コンパイル時に、静的な最終的なパブリック変数として変換されます。ただし、プリミティブ型よりも遅くなります。それを避けるようにしてください。

@JvmField val foo = Foo()

これは受け入れられる答えになるはずです。とにかく次のような場合:public static final Pattern REGEX_NOTEMPTY = Pattern.compile( "。+")????
ザン

24

コンパイル時にわかっている値は、定数としてマークすることができます(私の意見ではそうする必要があります)。

命名規則はJavaの規則に従う必要があり、Javaコードから使用したときに適切に表示される必要があります(コンパニオンオブジェクトを使用して達成するのは難しいですが、とにかく)。

適切な定数宣言は次のとおりです。

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

3
Naming conventions should follow Java ones- なぜ?
ジョディモロ2017年

3
Kotlinは通常、特に指定がない限り、相互運用を円滑にするために、デフォルトでJavaの規則に従います。
zsmb13

4
ドキュメントでそのように指定されている@Jodimoro kotlinlang.org/docs/reference/coding-conventions.html
Neil

2
@ニール、そうではない。
Jodimoro、

13
そのリンクで私が投稿した彼らは言うIf in doubt, default to the Java Coding Conventions
Neil

16

Kotlinで定数を宣言するために、クラス、オブジェクト、またはコンパニオンオブジェクトは必要ありません。すべての定数を保持するファイル(たとえば、Constants.ktまたは既存のKotlinファイル内に置くこともできます)を宣言して、ファイル内で定数を直接宣言することができます。コンパイル時に既知の定数は、でマークする必要がありますconst

したがって、この場合は次のようになります。

const val MY_CONST = "something"

次に、次のコマンドを使用して定数をインポートできます。

import package_name.MY_CONST

このリンクを参照できます


13
定数は、関連するクラスに含まれている必要があります。「定数」クラスを作成すると、最終的に、その中にある数百の定数が終了します。Pe:MAX_WIDTH、MAX_HEIGHTはScreenクラスになければならないので、論理的にそれにアクセスできます:Screen.MAX_WIDTHそして、Constants.SCREEN_MAX_WIDTHを置く必要はありません。オートコンプリートするためにCtrl + spaceを押すと、数百/数千行下にスクロールします。真剣に:それをしないでください。
メンテナンス不能性に

1
@inigoD定数を1か所または子だけで使用する場合は真実ですが、これはほとんど当てはまりません。不明瞭なクラスに定数を置くと、そのことを忘れたり、コードベースを引き継ぐ可能性が高くなったり、それらを複製する可能性があります。または、どこに配置するかが明確ではありません。ソースまたは宛先?見つけやすい定数ファイルをいくつか作成できます。設定キー、要求キーに対して1つのビュー定数のための1つ等のための一
Herrbert74

1
@ Herrbert74すみませんが、私はあなたに同意しなければなりません。どちらがそうであるかを見つけるのが難しい場合もありますが、定数の場所は常にそれに関連するクラスである必要があることに同意します。そして、それらをランダムに乱数ファイルに保存することは、後でそれらを取得したい場合、最良の方法ではありません...それらはランダムに保存されないが、パッケージには定数が関連していると主張しますが、これは単なる言い訳です彼らが関係しているクラスにそれらを入れないでください、最後に、彼らの場所...
inigoD '31

4
定数が本当にグローバルであるか、またはすべてのパッケージで使用される注釈の値、または複数のコントローラーによってフェッチされているヘッダー名など、スコープが大きい場合、「定数を作成することは完全に許容されます。スコープが適切なクラス」。ただし、特定のコンテキストでのみ使用される定数は、そのコンテキストにスコープを設定し、関連するクラスで宣言する必要があります。
Nephthys76

@ Nephthys76ちょうどメモとして、「すべてのパッケージで使用されるアノテーションの値などについては、特に、定数の最適な場所はアノテーションクラスにあると言えます。
スロー

8

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

これは本当ですか?誰でもこの方法で何か経験がありますか?
Scott Biggs

5
class Myclass {

 companion object {
        const val MYCONSTANT = 479
}

constキーワードを使用@JvmFieldするか、Javaの静的な最終定数にするを使用するか、2つの選択肢があります。

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

5

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)

1
グローバルメソッドまたは静的メソッドを定義する方法
サマドタルクダー

@SamadTalukderでKotlin楽しかっsumValue(V1:INT、V2:INT):なりのInt {戻りV1 + V2}
聖武天皇

5

と同様にvalconstキーワードで定義された変数は不変です。ここでの違いはconst、コンパイル時に既知である変数に使用されることです。

変数の宣言は、Javaでconststaticキーワードの使用とよく似ています。

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


4

どの回答にも記載されていないものは、を使用することによるオーバーヘッドですcompanion objectsここで読むことができるように、コンパニオンオブジェクトは実際にはオブジェクトであり、それらを作成するとリソースが消費されます。さらに、定数を使用するたびに、複数のゲッター関数を実行する必要がある場合があります。必要なのがいくつかのプリミティブ定数だけである場合は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));
    }
}

したがって、それらを避けてください。


3

ローカル定数:

const val NAME = "name"

グローバル定数:

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

MyConstants.NAMEにアクセス


1

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

したがって、これは定数を作成するための最良の方法です。


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!"
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.