当前位置: 首页 > news >正文

Java常量池理解

Java常量池理解

常量池分为两种:静态常量池和运行时常量池。

静态常量池

每个类在编译之后都会生成class文件,而class文件中就包含有静态常量池,分析class文件,如下图所示:

由于常量池中的常量的数量不是固定的,所以常量池的入口需要放置一项u2类型的数据,代表常量池的容量计数值。这里的常量池容量计数值是从1开始的。如图常量池的容量:0x001d(29)。所以共有29个常量。

运行时常量池

静态常量池编译完成之后就会保存再class文件中,当class文件中类被加载到内存中的时候,静态常量池中的常量最终都会存放到运行时常量池中,我们最终使用的都是运行时常量池的常量。
在JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中;
在JDK7.0版本,字符串常量池被移到了堆中了。

静态常量池和运行时常量池的区别?

看名字基本上就可以猜出来,静态常量池中的常量是不能够改变的,编译完成之后就无法改变了,但是运行时常量池却可以在运行时动态添加,如使用String的intern()方法,这个方法就可以把String中的字符串字面量添加到常量池中去。

常量池的好处

  1. 空间考虑
    相同的常量只占用一块内存
  2. 时间考虑
    使用==判断字符串是否相等的时候,不用像equals()方法样去比较内容,而是直接比较地址就可以了,因为常量池中保证了不同的常量的地址一定不一样。

字符串常量的理解

案例1

public class test {
public static void main(String[] args) {
String s1="abc1";//此处是数字1
String s2="abc"+1;
System.out.println(s1==s2);// 第一次比较
String s3="ab";
String s4="c";
String s5="abc";
String s6=s3+s4;
System.out.println(s5==s6);// 第二次比较
}
}

结果:
true
false
“abc”+1都是字面量,字面量在编译生成class文件时,编译器会将他们两优化到一起,放到静态常量池中去,既然已经放到静态常量池中去了,那么运行时常量池必定会存在,而s2拿的时候,运行时常量池就已经存在了abc1,所以s1和s2拿到到字符串常量是相同的。
而后面s3+s4都是字符串对象的拼接而不是字面量,所以在编译的时候不会放到常量池中去。

案例2

public class test {
public static final String s1="abc";
public static final String s2="def";
public static void main(String[] args) {
String s3=s1+s2;
String s4="abcdef";
System.out.println(s3==s4);
}
}

结果:
true

从这里可以看出,只要是引用在编译期能够直接指向有且仅有一个常量时,这个时候引用就是字符串常量

案例3

public class test {
public static final String s1;
public static final String s2;
static{
s1="abc";
s2="def";
}
public static void main(String[] args) {
String s3=s1+s2;
String s4="abcdef";
System.out.println(s3==s4);
}
}

结果:
false

这种情况和上面情况不同,因为static代码块是在运行时才会执行的,所以在编译时s1,s2虽然是final修饰,但是没有被赋值,所以仍然还是变量。

基本类型数据都有常量池吗?

不是的,Float和Double就没有实现常量池,Integer是实现了常量池的。但是Integer和字符串常量池有点区别。区别如下:

public class test {
public static void main(String[] args) {
Integer i1=10;
Integer i2=10;
Integer i3=20;
Integer i11=new Integer(10);
Integer i22=new Integer(10);
Integer i33=new Integer(20);
System.out.println(i1==i2);
System.out.println(i1==i11);
System.out.println(i11==i22);
System.out.println(i3==(i1+i2));
System.out.println(i3==(i11+i22));
System.out.println(i33==(i1+i2));
System.out.println(i33==(i11+i22));
}
}

结果:
true
false
false
true
true
true
true
其他的都好理解,主要是i33==(i1+i2),这里要特别注意:
1. 只要Integer进行了运算符运算就是进行自动拆箱操作,也就是说将包装类拆成字面量
2. 只要是一个数值字面量和一个Integer进行表达式运算,则Integer也会自动拆箱
所以这里实际上是20==20的恒等式。

相关文章:

  • Dubbo入门介绍及学习笔记总结
  • 【SpringMVC】重定向和转向详解
  • ocr的场景应用--发票识别
  • Dubbo入门(四)Provider和Consumer的注解实现
  • dubbo分布式日志调用链追踪
  • 软件测试周刊(第87期):天下就没有偶然,那不过是化了妆的、戴了面具的必然。
  • 灵性图书馆:好书推荐-《把好运吸过来》
  • 关于Springboot的@Profile的写法以及多个profile的写法排坑(“!profile1 !profile2“ 的写法)
  • Dubbo 原理与部署
  • 文章概述美国APX511B音频分析仪
  • linux shell脚本基础语法(变量篇)
  • dubbo Can not lock the registry cache file
  • dubbo 自定义异常
  • Navicat 16.1 的新功能 - 第 2 部分
  • Dubbo之多协议、多注册中心、多版本。
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 【译】理解JavaScript:new 关键字
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • js继承的实现方法
  • js数组之filter
  • JS题目及答案整理
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • SpiderData 2019年2月16日 DApp数据排行榜
  • 安卓应用性能调试和优化经验分享
  • 基于组件的设计工作流与界面抽象
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​如何防止网络攻击?
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #NOIP 2014#Day.2 T3 解方程
  • $.ajax,axios,fetch三种ajax请求的区别
  • (20050108)又读《平凡的世界》
  • (4.10~4.16)
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (已解决)什么是vue导航守卫
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • .NET Core 中插件式开发实现
  • .NET/C# 的字符串暂存池
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .net的socket示例
  • .net反编译工具
  • .NET开发者必备的11款免费工具
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .NET微信公众号开发-2.0创建自定义菜单
  • @Transaction注解失效的几种场景(附有示例代码)
  • @Validated和@Valid校验参数区别