ITmob-Ly
发布于 2023-06-29 / 111 阅读
0

Kotlin中 val 和 const val 有什么区别?

Kotlin-Blog

介绍

  1. val 是定义只读(Read-only)局部变量时使用的关键字,它定义的变量只能被赋值一次,相当于 Java 中修饰变量的 final 关键字。

val 属性可以在运行时初始化,因此可以将函数或某个类赋值给 val 变量。

  1. const val 是编译时常量(Compile-Time Constants),如果只读的值在编译时已知,使用 const 修饰符将其标记为编译时常量。

const val 定义的常量需要满足以下三个要求:

  1. 它必须是顶级属性(top-level property)、objectcompanion 对象的成员。
  2. 它必须使用 String 类型或基础类型的值进行初始化。
  3. 它不能是自定义 getter

从 Kotlin 1.1 开始,Kotlin 编译器会将 const val 值内联到使用它们的位置,将常量的引用替换为它的实际值. 但是常量对应的域变量不会被删除, 因此可以通过使用反射与它进行交互.

val 和 const val 的区别

我们可以通过 Kotlin 生成的编译后的字节码,查看两者之间区别。

例如在 PropertiesSample.Kt Kotlin 文件中定义一个只读属性和一个编译时常量:

package cn.itmob.sample.properties

val domainName: String = "itmob.cn"
const val DOMAIN_NAME: String = "itmob.cn"

反编译 Kotlin 代码生成的类文件:

public final class PropertiesKt {
   @NotNull
   private static final String domainName = "itmob.cn";
   @NotNull
   public static final String DOMAIN_NAME = "itmob.cn";

   @NotNull
   public static final String getDomainName() {
      return domainName;
   }
}

两个值都定义为了 final,唯一的区别是 const val 被声明为 public,但 valprivate 而且定义了一个 getter。

在 Java 类中它们的用法:

public class PropertiesSample {

    public static void main(String[] args) {
        System.out.println(PropertiesKt.getDomainName());
        System.out.println(PropertiesKt.DOMAIN_NAME);
    }
}

在 Kotlin 中的用法:

package cn.itmob.sample.properties

fun main() {
    println(domainName)
    println(DOMAIN_NAME)
}

反编译后是这样的:

public final class PropertiesKt {

   public static final void main() {
      String var0 = domainName;
      System.out.println(var0);
      var0 = "itmob.cn";
      System.out.println(var0);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

const val 值内联到了使用它的位置

总结

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