final修饰符是否存在定义缺陷?附Java递归静态代码谜题解析
Java静态递归初始化谜题解析
嘿,来看看这道有意思的Java静态初始化谜题,先猜猜下面这段代码运行后会输出啥?
public class RecursiveStatic { public static void main(String[] args) { System.out.println(scale(5)); } private static final long X = scale(10); private static long scale(long value) { return X * value; } }
答案:0
解析过程
是不是有点出乎意料?咱们一步步拆解背后的逻辑:
- Java类加载时,静态成员的初始化有固定顺序:先在准备阶段给静态字段分配内存并设置默认值(long类型默认是0),之后才在初始化阶段执行赋值语句。
- 当JVM处理
private static final long X = scale(10);时,会调用scale(10)方法,但此时X还没完成赋值,只能用默认值0。 scale(10)方法返回0 * 10 = 0,于是X被正式初始化为0。- 后续
main方法调用scale(5),此时X已经是0,所以返回0 * 5 = 0,最终输出0。
如果调整代码,把X的定义改成private static final long X = scale(10) + 3;,同时在scale方法里打印X,你会看到先输出X = 0,最终X的结果是3。这看似违背了final的不可变特性?其实不然——final的约束是初始化完成后不能修改,而初始化过程中字段会先持有默认值,直到赋值表达式执行完毕,这是Java类加载机制的正常行为,只是递归初始化的场景放大了这个细节而已。
内容的提问来源于stack exchange,提问作者Little Helper
相关产品推荐
相关产品推荐

