【Dart】Dart语言中常量final和const关键字详解(跟Java对比)

在Dart语言中,有两个声明常量的修饰符即final和const,它们都能表示常量,一旦赋值就不能再重新赋值,那么这两种常量有什么区别呢?

要弄懂它们的区别,先要理解什么是编译时常量,什么是运行时常量。

编译时常量,就是它的值在编译时就能确定的常量,不是等到运行时才确定。
运行时常量,就是在它的值在程序运行时才能确定。

const是编译时常量,final就是运行时常量。

在Java语言中没有这两种常量的区分,只有final类型修饰的常量。但是Java中的final既可以表示编译时常量也可以表示运行时常量。具体看它的初始值是不是8种基本数据类型或String类型的常量,是则是编译时常量,否则是运行时常量。

编译时常量有一个风险,就是当它的初始值引用了另外一个类的常量,当另外一个被引用的类在运行时替换了,那么引用它的那个编译时常量并不会受到影响。比如你的应用引用了一个jar包,这个jar包运行时可以动态替换,当你修改了jar中的常量,那么实际引用它的另外一个常量并不会被修改。

Java中的编译时常量示例:

class FinalDemo{
  public static final int test1=100;
  public static final long test2=1000l;
  public static final float test3=100.00f;
  public static final double test4=100.00d;
  public static final boolean test5=true;
  public static final String test6="hello";
  public static final char test7='a';
  public static final short test8=100;
}

Java中的运行时常量示例:

class FinalDemo2{
  public static final Integer test1=new Integer(100);
  public static final long test2=System.currentTimeMillis();
  public static final float test3=new Float(100.00f);
  public static final double test4=new Double(100.00d);
  public static final boolean test5=new Boolean("true");
  public static final String test6=new String("hello");
  public static final Character test7=new Character('a');
}

对于Java中的这种常量隐藏的风险,程序员很可能不小心就踩雷。

因此,Dart语言对这两个常量进行了区分:使用const表示的是编译时常量,final表示运行时常量。
那么在使用时有什么区别呢?

const修饰的常量必须在声明时初始化,并且是可以确定的值,不是需要经过计算的值。
final修饰的常量必须在声明进初始化或者在构造函数中初始化,它的值可以动态计算。

共同点是两者赋值后就不能再修改(不能重新赋值,对于引用类型可以修改属性)。

看一个Dart的常量实例:

main() {
  const test1="hello";//正确,编译期常量
  final test2="hello";//正确,运行时常量

  const test3=DateTime.now();//编译报错,值不是编译期常量
  final test4=DateTime.now();//正确,运行时常量

  const test5=new List();//编译报错,值不是编译期常量
  final test6=new List();//正确,运行时常量
}
### Dart 中 `const` `final` 的区别 #### 定义与作用范围 - **`final` 关键字** 使用 `final` 声明的变量在其生命周期内只能被赋值一次,无论是在声明时还是之后。一旦赋值完成,该变量的值便不可更改[^3]。这意味着 `final` 变量可以在运行时动态计算得出其值。 - **`const` 关键字** 使用 `const` 声明的是编译时常量,它不仅限于简单的数值类型,还可以表示复杂的对象结构(如列表、映射)。`const` 表达式的值必须在编译期就已知并固定下来,因此无法在运行时重新分配或修改[^2]。 #### 不可变性差异 - 对于 `final` 来说,虽然它可以指向一个不可变的对象(比如通过 `const` 构造出来的实例),但它本身并不强制要求所指代的内容一定是不可变的。换句话说,如果 `final` 绑定到一个可变集合上,则这个集合内部的数据仍然允许变化[^1]。 ```dart final List<int> numbers = [1, 2]; numbers.add(3); // 合法操作,numbers 列表内容发生了改变 ``` - 而对于 `const` ,由于它是真正的常量定义方式之一,所以由 `const` 初始化创建出来的东西总是完全不可变的,无论是原始数据类型还是复杂的数据结构都如此。 ```dart const List<int> constants = [4, 5]; // constants.add(6); // 错误:尝试向恒定列表添加新元素 ``` #### 性能考量 当多个地方需要用到相同的常数或者相同配置好的对象时,采用 `const` 更加高效,因为它会在整个应用程序范围内共享同一个内存地址副本而不是每次单独生成新的实体。而相比之下,即使两个不同位置上的 `final` 成员具有相等的实际内容,它们也各自独立存在互不影响。 ```dart void main() { final listA = ['apple', 'banana']; final listB = ['apple', 'banana']; print(identical(listA, listB)); // false const setA = {'red', 'blue'}; const setB = {'red', 'blue'}; print(identical(setA, setB)); // true } ``` --- ### 示例代码对比 以下是关于如何正确运用这两个关键词的一些例子: ```dart // 正确使用 final final String greetingMessage; greetingMessage = "Hello world!"; print(greetingMessage); // 尝试再次给 final 变量赋值会报错 // greetingMessage = "Goodbye"; // 正确使用 const const int daysInWeek = 7; // 下面这段不会执行成功,因为 const 必须立即初始化 /* const double piValue; piValue = 3.14159; */ // 复杂类型的比较 final Map<String, dynamic> userFinal = {"name": "Alice", "age": 25}; userFinal["city"] = "New York"; const Map<String, dynamic> userConst = {"name": "Bob", "age": 30}; // userConst["hobby"] = "Reading"; // 运行错误,试图更新 const 地图 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值