developer tip

Kotlin의 상수 —이를 만드는 데 권장되는 방법은 무엇입니까?

optionbox 2020. 8. 16. 20:11
반응형

Kotlin의 상수 —이를 만드는 데 권장되는 방법은 무엇입니까?


Kotlin에서 상수를 만드는 것이 어떻게 권장 되나요? 명명 규칙은 무엇입니까? 나는 문서에서 그것을 찾지 못했습니다.

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

    //2
    const val MY_CONST = "something"

    //3
    val myConst = "something"
}

아니면 ...?


Kotlin에서 클래스에서 사용되는 로컬 상수를 생성하려면 아래와 같이 생성 할 수 있습니다.

val MY_CONSTANT = "Constants"

그리고 java의 public static final 과 같이 kotlin에서 public 상수를 만들고 싶다면 다음과 같이 만들 수 있습니다.

companion object{

     const val MY_CONSTANT = "Constants"

}

컴패니언 개체를 사용하지 마십시오. 내부적으로 필드에 액세스 할 수 있도록 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


컴파일 타임에 알려진 값은 상수로 표시 될 수 있습니다 (내 의견으로는).

명명 규칙은 Java 규칙을 따라야하며 Java 코드에서 사용할 때 제대로 표시되어야합니다 (컴패니언 객체로는 달성하기 어렵지만 어쨌든).

적절한 상수 선언은 다음과 같습니다.

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

Kotlin에서 상수를 선언하기 위해 클래스, 객체 또는 동반 객체가 필요하지 않습니다. 모든 상수를 포함하는 파일 (예 : Constants.kt )을 선언하고 파일 내에서 직접 상수를 선언 할 수 있습니다. 컴파일 타임에 알려진 상수는로 표시되어야합니다 const.

따라서이 경우 다음과 같아야합니다.

const val MY_CONST = "something"

그런 다음 다음을 사용하여 상수를 가져올 수 있습니다.

import package_name.MY_CONST

링크를 참조 할 수 있습니다.


우선 상수에 대한 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를 저장할 전용 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()

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)

자바 디 컴파일 :

public final class MyClassKt {
    public static final int MY_CONST0 = 0;
    public static final int MY_CONST1 = 1;
}
// rest of MyClass.java

class Myclass {

 companion object {
        const val MYCONSTANT = 479
}

const키워드 를 사용 하거나 @JvmField자바의 정적 최종 상수를 만드는 두 가지 선택이 있습니다 .

class Myclass {

     companion object {
           @JvmField val MYCONSTANT = 479
    }

@JvmField주석을 사용하면 컴파일 후 Java에서 호출하는 방식으로 상수가 입력됩니다.
자바에서 호출하는 것처럼 컴파일러는 코드에서 동반 상수를 호출 할 때이를 대체합니다.

그러나 const 키워드를 사용하면 상수 값이 인라인됩니다. 인라인이란 컴파일 후 실제 값이 사용됨을 의미합니다.

요약하면 컴파일러가 수행 할 작업입니다.

//so for @JvmField:

Foo var1 = Constants.FOO;

//and for const:

Foo var1 = 479

답변에서 언급되지 않은 것은 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));
    }
}

그러니 그들을 피하십시오.


지역 상수 :

const val NAME = "name"

전역 상수 :

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

MyConstants.NAME에 액세스


프리미티브 및 문자열의 경우 :

/** 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에서 상수를 정의 할 수있는 몇 가지 방법이 있습니다.

컴패니언 개체 사용

    companion object {
        const val ITEM1 = "item1"
        const val ITEM2 = "item2"
    }

you can use above companion object block inside any class and define all your fields inside this block itself. But there is a problem with this approach, the documentation says,

even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects, and can, for example, implement interfaces.

When you create your constants using companion object, and see the decompiled bytecode, you'll something like below,

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

From here you can easily see what the documentation said, even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects It's doing extra work than required.

Now comes another way, where we don't need to use companion object like below,

object ApiConstants {
      val ITEM1: String = "item1"
 }

Again if you see the decompiled version of the byte code of above snippet, you'll find something like this,

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

Now if you see the above decompiled code, it's creating get method for each variable. This get method is not required at all.

To get rid of these get methods, you should use const before val like below,

object ApiConstants {
     const val ITEM1: String = "item1"
 }

Now if you see the decompiled code of above snippet, you'll find it easier to read as it does the least background conversion for your code.

public final class ApiConstants {
    public static final String ITEM1 = "item1";
    public static final ApiConstants INSTANCE;

    private ApiConstants() {
     }

    static {
        ApiConstants var0 = new ApiConstants();
        INSTANCE = var0;
      }
    }

So this is the best way to create constants.

참고URL : https://stackoverflow.com/questions/44038721/constants-in-kotlin-whats-a-recommended-way-to-create-them

반응형