编译时常量


class Example1d {

    static final int angle = 35;
    static final int length = angle * 2;
}

When the Example1d class is loaded by a Java Virtual Machine, angle and length are not stored as class variables in the method area


Java语言(由Java语言规范所规定的)有常量表达式的概念。这里所认可的常量很重要的一个方面就是它们都是值语义的。值语义意味着你只关心某个数据的值,不关心它的“身份”(identity);也就是说无论存在哪里、有多少份拷贝、是不是同一份拷贝都好,只要值相等你就会认为它们是“相同”的。


那么回过头来看些例子。留意声明的一侧跟使用的一侧不一定是对等的。

如果有:
Java代码 复制代码  收藏代码
  1. public class Foo {  
  2.     public static final int BAR = 1;  
  3.     public static final int BAZ = 42;  
  4.     public static final int GOO = 256;  
  5.     public static final int QUUX = 65536;  
  6. }  
public class Foo {
    public static final int BAR = 1;
    public static final int BAZ = 42;
    public static final int GOO = 256;
    public static final int QUUX = 65536;
}

(留意这是声明的一侧)

那么随便找个别的方法来看这些常量要访问的话会用怎样的字节码。
(接下来是使用的一侧)
Java代码 复制代码  收藏代码
  1. int i = Foo.BAR;  
int i = Foo.BAR;

这个语句的右手边的常量表达式会变成:
Java代码 复制代码  收藏代码
  1. iconst_1  
iconst_1

常量1就嵌在指令里了,而且不是作为指令的参数,而是指令本身就嵌着“1”这个常量值

Java代码 复制代码  收藏代码
  1. int i = Foo.BAZ;  
int i = Foo.BAZ;

这个语句的右手边的常量表达式会变成:
Java代码 复制代码  收藏代码
  1. bipush 42  
bipush 42

常量42作为指令bipush的参数嵌在字节码里

Java代码 复制代码  收藏代码
  1. int i = Foo.GOO;  
int i = Foo.GOO;

这个语句的右手边的常量表达式会变成:
Java代码 复制代码  收藏代码
  1. sipush 256  
sipush 256

常量256作为参数嵌在字节码里

Java代码 复制代码  收藏代码
  1. int i = Foo.QUUX;  
int i = Foo.QUUX;

这个语句的右手边的常量表达式会变成:
Java代码 复制代码  收藏代码
  1. ldc #2  
ldc #2

常量65536存在常量池里的第2项(这个常量池项的编号是我随便选的,无所谓)。

所以你会发现正常(非反射)去访问这些常量的时候,它们可能的形态就有好多种;其中小常量是尽量不放在常量池里的。
当然,因为字节码概念上会存在方法区里,所以那些嵌在指令里的常量概念上也存在方法区里了。不过跟许多人想像的形式大概不一样吧。

而为了支持反射,同样的一份值会在类的元数据里也放上一份。对应到Class文件格式那就是Field里的 ConstantValue属性,具体的值会存在 声明该常量的类的常量池里(跟使用的一侧没关系)。
Java代码 复制代码  收藏代码
  1. ConstantValue_attribute {  
  2.     u2 attribute_name_index;  
  3.     u4 attribute_length;  
  4.     u2 constantvalue_index;  
  5. }  
ConstantValue_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 constantvalue_index;
}

(留意到constantvalue_index存的是个索引号,真正的常量值在这个索引号对应的常量池项)

这一份在运行时就会存在方法区里。

“不是只存在于声明常量的类的元数据里”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值