java中变量可多次赋值,常量(final修饰)编译期强制不可重赋值;static final才构成全局常量,需全大写命名;final只保证引用不变,不约束对象内容;配置类值应外部注入而非硬编码。
变量能改,常量不能改——这是最根本的执行约束
Java里,int count = 5; 是变量,后面写 count = 10; 没问题;而 final double PI = 3.14159; 是常量,一旦赋值完成,再写 PI = 3.14; 就会编译报错:cannot assign a value to final variable PI。这不是风格建议,是编译器强制拦截——final 修饰的变量在字节码层面被标记为“不可重绑定”,JVM 不允许第二次写入。
- 变量可多次赋值,但每次赋值必须与声明类型兼容(比如
int不能直接存3.14) - 常量必须在声明时或构造器中完成初始化,否则编译失败(
variable PI might not have been initialized) - 哪怕用反射强行修改
final字段,也只影响当前对象实例,且破坏了 JVM 的常量池优化逻辑,生产环境严禁
static final 才算真正“全局可用”的常量
只写 final String DB_URL = "jdbc:mysql://..."; 在类里,它只是个“实例常量”,每个对象都有一份副本;要让所有地方都能直接用 MyConfig.DB_URL,必须加 static:public static final String DB_URL = "jdbc:mysql://...";。否则你在另一个类里写 MyConfig.DB_URL,编译器会报错:non-static variable DB_URL cannot be referenced from a static context。
-
static final常量在类加载时进入方法区(JDK 8+ 是元空间),值被内联进调用处(编译期优化),所以修改后必须重新编译所有引用它的类 - 如果常量是基本类型或字符串字面量(如
"timeout"),还会进字符串常量池,多个类引用同一static final String实际指向同一个对象 - 避免把大对象(比如
new HashMap())直接塞进static final,除非明确需要共享且线程安全——更推荐用private static final+ 静态块初始化
命名和作用域:一眼分清谁该在哪用
Java 没有语法强制要求常量大写,但所有主流规范(Google Java Style、Oracle Code Conventions)都约定:static final 常量全大写+下划线,比如 MAX_RETRY_COUNT;普通变量用驼峰,比如 retryCount。IDE(如 IntelliJ)甚至会把小写的 final 变量标黄警告:“Constant name does not follow naming convention”。