Java常量池理解与总结

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

一.相关概念


  1. 什么是常量
  2. 用final修饰的成员变量表示常量,值一旦给定就无法改变!
  3. final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。
  4. Class文件中的常量池
  5. 在Class文件结构中,最头的4个字节用于存储魔数Magic Number,用于确定一个文件是否能被JVM接受,再接着4个字节用于存储版本号,前2个字节存储次版本号,后2个存储主版本号,再接着是用于存放常量的常量池,由于常量的数量是不固定的,所以常量池的入口放置一个U2类型的数据(constant_pool_count)存储常量池容量计数值。
  6. 常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:
  • 类和接口的全限定名
  • 字段名称和描述符
  • 方法名称和描述符
  1. 方法区中的运行时常量池
  2. 运行时常量池是方法区的一部分。
  3. CLass文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
  4. 运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。
  5. 常量池的好处
  6. 如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:787707172,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。
  7. 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
  8. 例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
  9. (1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
  10. (2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。
  11. 双等号==的含义
  12. 基本数据类型之间应用双等号,比较的是他们的数值。
  13. 复合数据类型(类)之间应用双等号,比较的是他们在内存中的存放地址。

二.8种基本类型的包装类和常量池


  1. java中基本类型的包装类的大部分都实现了常量池技术,
  2. 即Byte,Short,Integer,Long,Character,Boolean;
Integer i1 = 40;Integer i2 = 40;System.out.println(i1==i2);//输出TRUE

这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。

//Integer 缓存代码 :
public static Integer valueOf(int i) {assert IntegerCache.high >= 127;if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}Integer i1 = 400;Integer i2 = 400;System.out.println(i1==i2);//输出false
  1. 两种浮点数类型的包装类Float,Double并没有实现常量池技术。
Double i1=1.2;Double i2=1.2;System.out.println(i1==i2);//输出false
  1. 应用常量池的场景
  2. (1)Integer i1=40;Java在编译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,从而使用常量池中的对象。
  3. (2)Integer i1 = new Integer(40);这种情况下会创建新的对象。
Integer i1 = 40;Integer i2 = new Integer(40);System.out.println(i1==i2);//输出false
  1. Integer比较更丰富的一个例子
Integer i1 = 40;Integer i2 = 40;Integer i3 = 0;Integer i4 = new Integer(40);Integer i5 = new Integer(40);Integer i6 = new Integer(0);System.out.println("i1=i2 " + (i1 == i2));System.out.println("i1=i2+i3 " + (i1 == i2 + i3));System.out.println("i1=i4 " + (i1 == i4));System.out.println("i4=i5 " + (i4 == i5));System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); System.out.println("40=i5+i6 " + (40 == i5 + i6)); 
i1=i2 true
i1=i2+i3 true
i1=i4 false
i4=i5 false
i4=i5+i6 true
40=i5+i6 true

解释:语句i4 == i5 + i6,因为+这个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。

Java中的自动装箱与拆箱

三.String类和常量池


  1. String对象创建方式
String str1 = "abcd";String str2 = new String("abcd");System.out.println(str1==str2);//false

这两种不同的创建方法是有差别的,第一种方式是在常量池中拿对象,第二种方式是直接在堆内存空间创建一个新的对象。

只要使用new方法,便需要创建新的对象。

  1. 连接表达式 +
  2. 如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:787707172,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。
  3. (1)只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。
  4. (2)对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。
String str1 = "str";String str2 = "ing";String str3 = "str" + "ing";String str4 = str1 + str2;System.out.println(str3 == str4);//falseString str5 = "string";System.out.println(str3 == str5);//true

java基础:字符串的拼接

  • 特例1
public static final String A = "ab"; // 常量A
public static final String B = "cd"; // 常量B
public static void main(String[] args) {String s = A + B; // 将两个常量用+连接对s进行初始化 String t = "abcd"; if (s == t) { System.out.println("s等于t,它们是同一个对象"); } else { System.out.println("s不等于t,它们不是同一个对象"); } } 
s等于t,它们是同一个对象

A和B都是常量,值是固定的,因此s的值也是固定的,它在类被编译时就已经确定了。也就是说:String s=A+B; 等同于:String s="ab"+"cd";

  • 特例2
public static final String A; // 常量A
public static final String B; // 常量B
static { A = "ab"; B = "cd"; } public static void main(String[] args) { // 将两个常量用+连接对s进行初始化 String s = A + B; String t = "abcd"; if (s == t) { System.out.println("s等于t,它们是同一个对象"); } else { System.out.println("s不等于t,它们不是同一个对象"); } } 
s不等于t,它们不是同一个对象

A和B虽然被定义为常量,但是它们都没有马上被赋值。在运算出s的值之前,他们何时被赋值,以及被赋予什么样的值,都是个变数。因此A和B在被赋值之前,性质类似于一个变量。那么s就不能在编译期被确定,而只能在运行时被创建了。

  1. String s1 = new String("xyz"); **创建了几个对象? **
  2. 考虑类加载阶段和实际执行时。
  3. (1)类加载对一个类只会进行一次。"xyz"在类加载时就已经创建并驻留了(如果该类被加载之前已经有"xyz"字符串被驻留过则不需要重复创建用于驻留的"xyz"实例)。驻留的字符串是放在全局共享的字符串常量池中的。
  4. (2)在这段代码后续被运行的时候,"xyz"字面量对应的String实例已经固定了,不会再被重复创建。所以这段代码将常量池中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s1 持有。
  5. 这条语句创建了2个对象。
  6. java.lang.String.intern()
  7. 运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。
  8. String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。
public static void main(String[] args) { String s1 = new String("计算机");String s2 = s1.intern();String s3 = "计算机";System.out.println("s1 == s2? " + (s1 == s2));System.out.println("s3 == s2? " + (s3 == s2));}
s1 == s2? false
s3 == s2? true
  1. 字符串比较更丰富的一个例子
public class Test {public static void main(String[] args) { String hello = "Hello", lo = "lo";System.out.println((hello == "Hello") + " ");System.out.println((Other.hello == hello) + " ");System.out.println((other.Other.hello == hello) + " ");System.out.println((hello == ("Hel"+"lo")) + " ");System.out.println((hello == ("Hel"+lo)) + " ");System.out.println(hello == ("Hel"+lo).intern());} 
}
class Other { static String hello = "Hello"; }
package other;
public class Other { public static String hello = "Hello"; }
true true true true false true```
在同包同类下,引用自同一String对象.
在同包不同类下,引用自同一String对象.
在不同包不同类下,依然引用自同一String对象.
在编译成.class时能够识别为同一字符串的,自动优化成常量,引用自同一String对象.
在运行时创建的字符串具有独立的内存地址,所以不引用自同一String对象.

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:787707172,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

 

转载于:https://my.oschina.net/u/3990817/blog/3029815

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252023.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

转载:https://blog.csdn.net/dcrmg/article/details/52939318

张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析&#xff08;附标定程序和棋盘图&#xff09;使用Opencv实现张正友法相机标定之前&#xff0c;有几个问题事先要确认一下&#xff0c;那就是相机为什么需要标定&#xff0c;标定需要的输…

Redis学习笔记--Redis数据过期策略详解==转

本文对Redis的过期机制简单的讲解一下  讲解之前我们先抛出一个问题&#xff0c;我们知道很多时候服务器经常会用到redis作为缓存&#xff0c;有很多数据都是临时缓存一下&#xff0c;可能用过之后很久都不会再用到了&#xff08;比如暂存session&#xff0c;又或者只存放日行…

会员连锁配置以及金额走向

PS&#xff1a;所有电子支付方式的资金走向都是同样的&#xff0c;配置的是什么支付方式就走什么支付方式;下面以支付宝为例说明 一、连锁非总机模式 资金走向&#xff1a; 支付宝&#xff1a;收到的钱在主账号配置的支付宝&#xff0c;会员卡的金额在主账号 微信&#xff1a;收…

C# 多线程及同步简介示例

60年代&#xff0c;在OS中能拥有资源和独立运行的基本单位是进程&#xff0c;然而随着计算机技术的发展&#xff0c;进程出现了很多弊端&#xff0c;一是由于进程是资源拥有者&#xff0c;创建、撤消与切换存在较大的时空开销&#xff0c;因此需要引入轻型进程&#xff1b;二是…

Spring Framework 5.1.6、5.0.13 与 4.3.23 发布

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; Spring Framework 5.1.6、5.0.13 与 4.3.23 发布了。 v5.1.6 包含 49 个 bug 修复和功能改进&#xff1b;v5.0.13 是 5.0.x 系列的最后一个版本&#xff0c;包含了 25 个 bug 修复和功能改进&am…

单目视觉标定:世界坐标系、相机坐标系、图像坐标系、像素坐标系——简单粗暴,粗暴

转&#xff1a;https://blog.csdn.net/chentravelling/article/details/53558096 1.正文 图像处理、立体视觉等等方向常常涉及到四个坐标系&#xff1a;世界坐标系、相机坐标系、图像坐标系、像素坐标系。例如下图&#xff1a; 构建世界坐标系只是为了更好的描述相机的位置在哪…

VSFTP的使用

一、基本安装 1.安装服务 yum -y install vsftpd //centos Redhat apt-get install vsftpd //debian ubuntu 2.开启服务 service vsftpd status //查看状态&#xff0c;默认是关闭的 service vsftpd start 3.开机随操作系统启动 chkconfig vsftpd on4.添加账号 useradd -d /…

OC Swift混编-Swift.h File not found

https://www.jianshu.com/p/f860fe1718ca 2016.09.13 11:53* 字数 266 阅读 1935评论 1喜欢 1今天碰到个神坑,本人项目是OC项目,最近开始使用Swift开始替代.但是,在替代的已开始就出现问题了:新建swift文件,然后提示创建bridging-Hearder文件,然后swift可以使用OC代码了.这些都…

视觉标定,再来一波!!更简单粗暴!!!!!!

继续&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 一、四个坐标系简介和转换 相机模型为以后一切标定算法的关键&#xff0c;只有这边有相当透彻的理解&#xff0c;对以后的标定算法才能有更好的理解。本人研究了好长时间&#xff0c;几乎每天…

深入浅出NIO之Selector实现原理

2019独角兽企业重金招聘Python工程师标准>>> 前言 Java NIO 由以下几个核心部分组成&#xff1a; 1、Buffer 2、Channel 3、Selector Buffer和Channel在深入浅出NIO之Channel、Buffer一文中已经介绍过&#xff0c;本文主要讲解NIO的Selector实现原理。 之前进行sock…

介绍一下画图小能手matplotlib。

我们在做完数据分析的时候需要把分析出来的结果&#xff0c;做一个图形化的形象表达&#xff0c;这里我们就需要用到画图小能手matplotlib&#xff0c;下面就演示一下常用的条形图和折线图 散点图 散点图的做大的作用是研究两个变量的相关性&#xff08;正相关&#xff0c;负相…

立体视觉标定源代码C++,简单粗暴!粗暴·······

疑点解答&#xff1a; 摄像机矩阵由内参矩阵和外参矩阵组成&#xff0c;对摄像机矩阵进行QR分解可以得到内参矩阵和外参矩阵。 内参包括焦距、主点、倾斜系数、畸变系数 &#xff08;1&#xff09; 其中&#xff0c;fx&#xff0c;fy为焦距&#xff0c;一般情况下&#xff…

MongoDB负载信息一目了然 阿里云HDM重磅发布MongoDB监控和诊断功

2019独角兽企业重金招聘Python工程师标准>>> 混合云数据库管理&#xff08;HDM&#xff09;的统一监控、告警、诊断功能新增了对MongoDB的支持。 通过直观的方式将MongoDB多个维度的负载信息统一整合&#xff0c;不仅可以清晰的查看实时负载信息&#xff0c;也可以方…

在iview的Table中添加Select(render)

首先对Render进行分析&#xff0c;在iview官方的文档中&#xff0c;找到了table插入Button的例子&#xff1a; [javascript] view plaincopy { title: Action, key: action, width: 150, align: center, render: (h, params) > { return h(div, [ h(Butt…

工业机械人运动学正逆解,简单粗暴!!!!!!

ur机械臂是六自由度机械臂&#xff0c;由D-H参数法确定它的运动学模型&#xff0c;连杆坐标系的建立如上图所示。 转动关节θi是关节变量&#xff0c;连杆偏移di是常数。 关节编号 α&#xff08;绕x轴&#xff09; a&#xff08;沿x轴&#xff09; θ&#xff08;绕z轴&am…

python opencv立体测距 立体匹配BM算法

立体标定应用标定数据转换成深度图标定 在开始之前&#xff0c;需要准备的当然是两个摄相头&#xff0c;根据你的需求将两个摄像头进行相对位置的固定&#xff0c;我是按平行来进行固定的&#xff08;如果为了追求两个双目图像更高的生命度&#xff0c;也可以将其按一定钝角固…

Vue基础学习(一)------内部指令

一.v-if v-else v-show 指令 1.v-if v-if:是vue 的一个内部指令&#xff0c;指令用在我们的html中,用来判断是否加载html的DOM 现在举个栗子&#xff0c;判断用户的登录操作&#xff0c;用isLogin作为一个判断字段&#xff0c;登录成功&#xff0c;就显示用户的名称 代码&…

StereoRectify()函数定义及用法畸变矫正与立体校正

畸变矫正是上一篇博文的遗留问题&#xff0c;当畸变系数和内外参数矩阵标定完成后&#xff0c;就应该进行畸变的矫正&#xff0c;以达到消除畸变的目的&#xff0c;此其一。 在该系列第一部分的博文中介绍的立体成像原理中提到&#xff0c;要通过两幅图像估计物点的深度信息&a…

死磕 java集合之TreeMap源码分析(三)- 内含红黑树分析全过程

2019独角兽企业重金招聘Python工程师标准>>> 欢迎关注我的公众号“彤哥读源码”&#xff0c;查看更多源码系列文章, 与彤哥一起畅游源码的海洋。 删除元素 删除元素本身比较简单&#xff0c;就是采用二叉树的删除规则。 &#xff08;1&#xff09;如果删除的位置有两…

四元素理解

旋转变换_四元数 2017年03月29日 11:59:38 csxiaoshui 阅读数&#xff1a;5686 1.简介 四元数是另一种描述三维旋转的方式&#xff0c;四元数使用4个分量来描述旋转&#xff0c;四元数的描述方式如下&#xff1a; qsxiyjzk,(s,x,y,z∈ℝ&#xff09;i2j2k2ijk−1 四元数的由…