final,static,const差异

做了这么多年的Java,一般也不想了解一些细枝末节的东西比如如题的这三个东西。面试的时候常常会问到,我才留了个心。最近在细看flutter的东西,看到这里边一个变量,居然用了final来修饰,果断问了下豆包,有了新的认知。

Future<void> _login() async {
	// 这里居然用了final来修饰一个变量,final不是不能修改的吗?
    final Map<String, dynamic> data = {
      "account": _phoneController.text,
      "password": _codeController.text,
    };
    try {
      final response = await loginAPI(data);
      print(response);
      _userController.updateUserInfo(response);
      ToastUtils.showToast(context, "登录成功");
      Navigator.pop(context);
    } catch (e) {
      ToastUtils.showToast(context, (e as DioException).message ?? "登录异常");
    }
  }

问:这里可以用final修饰吗?
答:是的,这里可以使用 final 修饰。

分析

  • 可以使用 final:在这个场景下使用 final 是合适的
  • 推荐使用 final:因为这个 [data](file:///C:/GitHub/flutter_learn/lib/app/pages/login/index.dart#L207-L210) 变量在创建后不需要重新赋值
  • 性能优化final 修饰符可以防止意外的重新赋值,提高代码安全性

详细说明

// 当前代码 - 已经使用了 final(正确)
final Map<String, dynamic> data = {
  "account": _phoneController.text,
  "password": _codeController.text,
};
  • [data](file://C:\GitHub\flutter_learn\build\app\intermediates\flutter\debug\flutter_assets\vm_snapshot_data) 变量在初始化后只用于传递给 [loginAPI](file:///C:/GitHub/flutter_learn/lib/app/api/user_api.dart#L4-L8) 函数
  • 没有对该变量进行重新赋值的需求
  • 使用 final 符合不可变性原则,使代码更加安全和可预测

因此,当前代码中使用 final 的做法是正确的


问:但是这个对象中的值会随着用户输入的改变而变化,为什么还能用final修饰?

答:

关于 final 修饰 Map 的说明

1. final 与不可变性的理解

  • final 修饰变量引用:防止变量指向其他对象
  • 不修饰对象内容:Map 内部的值仍可以修改
  • 当前场景适用:[data](file:///C:/GitHub/flutter_learn/lib/app/pages/login/index.dart#L207-L210) 只用于 API 调用,无需后续修改

2. Dart 中的可变 vs 不可变

// final 修饰引用,但 Map 内容可变
final Map<String, dynamic> data = {"account": "123"};
data["account"] = "456"; // ✅ 允许修改内容
data = {}; // ❌ 不允许重新赋值

// 如需完全不可变,使用:
final Map<String, dynamic> immutableData = Map.unmodifiable({
  "account": _phoneController.text,
  "password": _codeController.text,
});

3. 当前代码的合理性

  • [data](file:///C:/GitHub/flutter_learn/lib/app/pages/login/index.dart#L207-L210) 作用域:仅在 _login() 方法内使用一次
  • 数据流向:从控制器获取 → 组装对象 → 传递给 API → 完成使命
  • 使用 final 正确:防止意外的变量重新赋值,保证引用不变

4. 总结

final 修饰的是变量引用而非对象内容,因此即使用户输入变化,[data](file:///C:/GitHub/flutter_learn/lib/app/pages/login/index.dart#L207-L210) 在创建时捕获的值也不会影响 final 的使用合理性。


问:Java中的final也是类似的意思吗?

答:

Java 中的 final 与 Dart 中的 final 对比

1. 相似性

  • 引用不变性:都用于防止变量引用被重新赋值
  • 对象内容可变:修饰的容器对象内部元素仍可修改
  • 编译时检查:都会在编译阶段检查是否违反 final 规则

2. Dart 中的 final

final Map<String, String> data = {"key": "value"};
data["key"] = "new value"; // ✅ 允许
data = {}; // ❌ 不允许

3. Java 中的 final

final Map<String, String> data = new HashMap<>();
data.put("key", "value"); // ✅ 允许
data = new HashMap<>(); // ❌ 不允许

4. 关键差异

  • 初始化时机:Java 支持在构造器中初始化 final 字段
  • 语法细节:Java 中 final 可用于类、方法、变量多个层面
  • 性能优化:Java 的 final 在 JVM 优化中作用更显著

5. 总结

  • 两种语言的 final 概念基本一致
  • 都是引用级别的不可变性
  • 容器内容的可变性在两种语言中都存在

问:final和static的异同?

finalstatic 的异同

相同点

  • 都用于修饰符:都是编程语言中的关键字
  • 限制性:都对被修饰的元素施加某种限制

不同点

final

  • 作用:修饰变量,表示不可变性
  • 生命周期:运行时检查,变量只能被赋值一次
  • 实例相关:通常用于实例变量或局部变量
  • Dart 示例
final String name = "user";
// name = "new"; // ❌ 编译错误

static

  • 作用:修饰成员,表示类级别而非实例级别
  • 内存分配:属于类本身,不依赖于实例
  • 访问方式:通过类名直接访问,无需实例化
  • Dart 示例
class MyClass {
  static String className = "MyClass";
  static void printInfo() {
    print("This is $className");
  }
}
// 访问:MyClass.className 或 MyClass.printInfo()

结合使用

  • static final:最常见组合,用于定义常量
  • Dart 示例
static final String API_URL = "https://api.example.com";

总结

  • final 关注可变性static 关注作用域
  • final 限制赋值次数,static 限制访问方式
  • 两者解决不同问题,可同时使用

问:static的访问方式有什么区别,应该是可变的吧?

static 访问方式的区别

访问方式对比

1. 访问途径

  • 类名访问ClassName.staticMember
  • 实例访问instance.staticMember(不推荐,但仍可行)

2. Dart 中的访问示例

class MyClass {
  static String className = "MyClass";
  static void printInfo() {
    print("Static method called");
  }
}

// 推荐方式
MyClass.className;
MyClass.printInfo();

// 技术上可行但不推荐
MyClass instance = MyClass();
instance.className;  // 不推荐

可变性说明

1. static 本身不保证不可变

  • 可变static var 或未使用 finalstatic 变量
  • 不可变static finalstatic const

2. 示例对比

class Config {
  // 可变的 static 变量
  static String apiUrl = "https://api.example.com";
  
  // 不可变的 static 常量
  static final String APP_NAME = "MyApp";
  static const int VERSION = 1;
}

// 可变 static 变量可以被修改
Config.apiUrl = "https://new-api.example.com"; // ✅ 允许

// 不可变 static 常量不能被修改
// Config.APP_NAME = "NewName"; // ❌ 编译错误

3. 实际情况

  • static 修饰的成员可以是可变的
  • 是否可变取决于是否使用 finalconst 修饰
  • static 只表示作用域(类级别),不表示可变性

总结

  • static 成员通过类名直接访问
  • static 本身不保证不可变性
  • 可变性由 final/const 关键字控制

问:

static final String APP_NAME = “MyApp”;
static const int VERSION = 1;
这两个final和const有什么区别

答:

finalconst 的区别

编译时 vs 运行时

  • const:编译时常量,在编译时确定值
  • final:运行时常量,在运行时首次赋值后不可变

内存分配差异

  • const:相同值的 const 对象共享内存,保证对象唯一性
  • final:每次创建新的对象实例,不保证唯一性

使用场景对比

static const

static const int VERSION = 1;  // 编译时已知的常量
  • 适用于编译时确定的常量值
  • 如数字、字符串字面量、布尔值等

static final

static final String APP_NAME = "MyApp";  // 运行时确定的常量
  • 适用于运行时计算的常量值
  • 如通过函数计算得到的值

初始化时机

  • const:必须在声明时确定值
  • final:可以在运行时任何时间点赋值(但只能赋值一次)

性能差异

  • const:编译时优化,内存占用更优
  • final:运行时初始化,灵活性更高

实际应用

在你的示例中:

  • static const int VERSION = 1 - 版本号是编译时常量
  • static final String APP_NAME = "MyApp" - 应用名通常也是编译时常量,可考虑改为 const

以上是对final,static,const的认识,祝好~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值