在Java中变量和常量有什么区别_Java变量与常量使用场景解析

变量可重新赋值,常量用final修饰且不可变引用;static final基本类型/String会被编译器内联,引用类型不会;公共常量须public static final,实例final字段仅为不可变状态而非共享常量。

变量声明后可以重新赋值,常量声明后不能修改

Java 中 变量 使用基本类型或引用类型声明,未加修饰符,默认可变;常量 必须用 final 修饰,且通常配合 static 和大写命名(如 MAX_RETRY)。一旦初始化完成,再对 final 变量赋值会触发编译错误:error: cannot assign a value to final variable

注意:这里的“不可变”仅指引用地址不可变。若 final List list = new ArrayList();,仍可调用 list.add("x") —— 因为对象内容可变,只是 list 不能再指向另一个 List 实例。

变量适合临时存储计算结果,常量适合定义配置或协议值

实际编码中,变量 多用于流程控制、中间计算、用户输入暂存等场景;常量 则用于避免魔法数字/字符串,提升可读与可维护性。

  • 用变量:循环计数器 i、HTTP 响应体 responseBody、解析后的 JSON 对象 data
  • 用常量:HTTP 状态码 HTTP_OK = 200、数据库表名 TABLE_USER = "user"、超时毫秒数 TIMEOUT_MS = 5000

特别提醒:如果常量值在运行时才能确定(比如从配置文件读取),就不能用 static final 编译期常量,而要用普通 final 字段 + 构造器/静态块初始化。

局部变量不加访问修饰符,类级常量通常用 public static final

作用域决定声明方式:

  • 方法内声明的变量是局部变量,不能加 public/private,也不需要 final(除非你明确禁止重赋值)
  • 类字段若要作为公共常量,必须是 public static final,否则其他类无法直接访问(如

    MyConfig.API_URL
  • static 是关键:没有它,每个实例都会有一份副本,失去“常量”的共享语义

反例:private final String DB_NAME = "prod_db"; 看似常量,但每个对象都存一份,且外部不可见,实际意义接近配置字段而非常量。

public class NetworkConfig {
    // ✅ 正确的公共常量
    public static final int CONNECT_TIMEOUT_MS = 3000;
    public static final String BASE_URL = "https://api.example.com";

    // ⚠️ 不推荐:非 static 的 final 字段不是“类常量”
    private final String apiKey; // 需通过构造器注入,属于实例状态

    public NetworkConfig(String apiKey) {
        this.apiKey = apiKey; // 只能赋值一次,但每个实例不同
    }
}

编译器会对 static final 基本类型/字符串做内联优化

当常量是 public static final 且类型为基本类型或 String,Javac 会在编译期把所有引用位置替换成字面值。例如:

源码中写 if (status == HttpStatus.OK),而 HttpStatus.OKpublic static final int OK = 200;,生成的字节码里直接出现 200,不走字段读取。

这个优化带来两个后果:

  • 如果常量定义在外部 jar 中,你更新了它的值但没重新编译依赖方,运行时仍用旧值
  • static final 引用类型(如 ListMap)不会被内联,因为对象地址无法在编译期确定

所以,涉及跨模块共享的常量,尤其是数字和字符串,务必确认上下游是否同步重建。