Java变量运行时解析、常量编译时解析概念及代码示例咨询
编译时解析 vs 运行时解析 通俗讲解
Java代码的执行分两个核心阶段:先通过javac命令编译成字节码文件,再交给JVM加载运行。你提到的这句话,本质就是常量和变量确定最终值的阶段不同。
1. 什么是「常量编译时解析」
编译时解析的常量需要满足两个条件:被final修饰,且声明时就赋值为固定字面量(不是方法返回值、new出来的对象这类运行时才能确定的值)。
编译阶段就会把代码中所有用到这个常量的位置直接替换成常量的字面量,相当于硬编码到字节码里,运行时不需要再去查这个常量的定义。
代码示例1:基础常量替换
public class CompileConstant { // 编译时常量 public static final int MAX_AGE = 18; public static void main(String[] args) { int age = 20; if (age > MAX_AGE) { System.out.println("成年"); } } }
编译后反编译字节码,会发现if判断直接变成了if(age > 18),字节码里已经没有MAX_AGE的引用了,相当于编译时就把常量替换成了具体值。
代码示例2:字符串常量折叠
public class StringConst { public static final String PREFIX = "Java"; public static void main(String[] args) { String s = PREFIX + "学习"; System.out.println(s == "Java学习"); // 输出true } }
编译时直接把PREFIX + "学习"优化成了字符串常量池中的"Java学习",所以用==比较引用也是相等的。
2. 什么是「变量运行时解析」
普通变量(没有final修饰,或者final修饰但值是运行时才能确定的),编译阶段无法确定最终值,也无法确定会不会被修改,只有运行到对应代码行时,才会从内存中读取当前变量的实际值。
代码示例1:普通成员变量
public class RuntimeVar { public int score = 60; public static void main(String[] args) { RuntimeVar s1 = new RuntimeVar(); s1.score = 90; RuntimeVar s2 = new RuntimeVar(); System.out.println(s1.score); // 运行时读取s1对象内存中的score值,输出90 System.out.println(s2.score); // 运行时读取s2对象内存中的score值,输出60 } }
编译时根本不知道每个实例的score会被改成多少,只有运行时才能拿到每个对象的实际属性值。
代码示例2:字符串变量拼接
public class StringVar { public String prefix = "Java"; public static void main(String[] args) { StringVar obj = new StringVar(); String s = obj.prefix + "学习"; System.out.println(s == "Java学习"); // 输出false } }
这里prefix是变量,编译时不会做优化,运行时才会拼接字符串生成新的对象,所以和常量池中的"Java学习"不是同一个引用,==比较为false。
3. 常见误区:不是所有final修饰的都是编译时常量
如果final修饰的字段赋值的是运行时才能确定的值,那它还是会在运行时解析:
public class FinalRuntime { // 虽然加了final,但值是运行时生成的随机数,编译时无法确定 public static final int RAND_NUM = (int) (Math.random() * 100); public static void main(String[] args) { System.out.println(RAND_NUM); // 每次运行输出的值都不一样 } }
核心总结
- 编译时解析:值在编译阶段就完全确定且不会修改,直接替换成字面量写入字节码,运行时不需要二次查询
- 运行时解析:值在编译阶段无法确定,或可能被修改,必须运行时从内存中读取当前的实际值
内容的提问来源于stack exchange,提问作者Vaibhav Rajoriya
相关产品推荐
相关产品推荐

