在java中,常量的定义、常量的存储位置、常量池概念、jvm内存结构、编译期和运行期

《Thinking in java》中这个常量指的是“Java ,这类常量必须是原始的

并且以关键字final 表示。在对这个常量进行定义的时候,必须对其进行赋值。

一个既是 static 又是final 域只占有一份不能改变的存储空间。”

 

编译期的值的确定“我们不能因为某数据是 final 的就认为在编译期可以知道它的值。在运行期使用随机生成的数值来初始化类的属性,就说明了这一点。”

 

“将final 数值定义为static 和非static 的区别。....编译期间的值被编译器认为是相同的。”

带有恒定初始值的final 原始类型(基本数据类型),即编译期常量

 

jvm虚拟内存分布:

     程序计数器jvm执行程序的流水线,存放一些跳转指令。

     本地方法栈jvm调用操作系统方法所使用的栈。

     虚拟机栈jvm执行java代码所使用的栈。

     方法区存放了一些常量、静态变量、类信息等,可以理解成class文件在内存中的存放位置。

     虚拟机堆jvm执行java代码所使用的堆。

 

 

Java中的常量池,实际上分为两种形态:静态常量池运行时常量池。

静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。

这种常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等

运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

 

Java语言并不要求常量一定只有编译期才能产生,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。

Stringintern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。

 

 

三个非常重要的结论:

        必须要关注编译期的行为,才能更好的理解常量池。

        运行时常量池中的常量,基本来源于各个class文件中的常量池。

        程序运行时,除非手动向常量池中添加常量(比如调用intern方法),否则jvm不会自动添加常量到常量池。

字符串常量池、整型常量池、浮点型常量池。(java中基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean两种浮点数类型的包装类Float,Double并没有实现常量池技术) 等等

比如整型常量池中的常量范围:-128~127,(Byte,Short,Integer,Long,Character,Boolean)这5种包装类默认创建了数值[-128127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。

 

总结:

         常量是在编译期存放在常量池中的。(面试常考:常量存放在什么地方?)

         我们常说的常量池,就是指方法区中的运行时常量池。

         运行时常量池在jvm内存结构的方法区中。

         因为常量是编译期可以得知的,在编译期会执行全是常量的计算式(编译器优化),把常量以及计算结果值(也是常量)存放在常量池中,减轻运行期的负担。

        

         方法调用和new是编译期无法得知的,不会放在常量池,而是在运行期放在堆内存中。

        

 

 

参考:

《Thinking in java》中final关键字。

https://www.cnblogs.com/syp172654682/p/8082625.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值