Java-常量池

相关概念

  1. 常量池的定义
    常量池(constant pool):指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。虚拟机必须为每个被装载的类维护一个常量池。常量池就是该类所用到常量的一个有序集和。常量池位于JVM的方法区中。
    常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References)
    字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)
    符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:
    类和接口的全限定名
    字段名称和描述符
    方法名称和描述符
  2. 常量池的好处
    常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。(2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。
  3. 常量池的分类
    java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。
    ** 静态常量池** 即编译生成的.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。
    运行时常量池 在程序执行的时候,常量池会储存在Method Area,而不是堆中.则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

String类和常量池

String s1 = "Hello";
String s2= new String("Hello");
System.out.println(s1 == s5);//false

这两种不同的创建方法是有差别的,第一种方式是字符串在编译期间放在了常量池中,第二种方式是直接在堆内存空间创建一个新的对象。显然这两个对象的地址时不同的。

String s1 = "Hello";
String s2 = "Hel" + "lo";
String s3 = "Hel" + new String("lo");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s2 == s3);//false

s1在编译期间放在了常量池中。
s2虽然是动态拼接出来的字符串,但是所有参与拼接的部分都是已知的字面量,在编译期间,这种拼接会被优化,编译器直接帮你拼好,因此String s2 = "Hel" + "lo";在class文件中被优化成String s2 = "Hello",并放在了常量池中。
s3虽然也是拼接出来的,但new String("lo")这部分不是已知字面量,是一个不可预料的部分,编译器不会优化,必须等到运行时才可以确定结果,并分配在堆中。

String s1 = "Hello";    
String s2 = "H";
String s3 = "ello";
String s4 = s7 + s8;                   
System.out.println(s1 == s4);  // false

虽然s2、s3在赋值的时候使用的字符串字面量,但是拼接成s4的时候,s2、s3作为两个变量,都是不可预料的,编译器毕竟是编译器,不可能当解释器用,所以不做优化,等到运行时,s2、s3拼接成的新字符串,在堆中地址不确定,不可能与方法区常量池中的s1地址相同。
总结:

  1. 常量池中的两个字符串相等
  2. 常量池和堆中的字符串不相等
  3. 堆中的两个字符串不相等

运行时常量池相对于class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。
String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。

String s1 = "Hello";    
String s2 = new String("Hello"); 
String s3 = s2.intern();
System.out.println(s1 == s2);//false
System.out.println(s1 == s3);  // true

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

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

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

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. 应用常量池的场景
    (1) Java在编译的时候会直接将代码封装,从而使用常量池中的对象。valueOf方法中也有判断,若数值范围在[-128,127]内,就会从常量池中取值返回,否则就会返回一个新的Integer对象。即在堆内存中分配内存。
Integer i1=40;
Integer i1=Integer.valueOf(40);
//这两句等价

(2)此情况下会创建新的对象。

Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);//输出false

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));//true
System.out.println("i1=i2+i3 " + (i1 == i2 + i3));//true
System.out.println("i1=i4 " + (i1 == i4));// false
System.out.println("i4=i5 " + (i4 == i5));// false
System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); //true
System.out.println("40=i5+i6 " + (40 == i5 + i6));//true

解释:语句

i4 == i5 + i6

因为+这个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即

i4 == 40

然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为

40 == 40

进行数值比较。

  1. 基本类型与其包装类进行比较,包装类会自动拆箱成相应基本类型,然后比较值即可
int i=0;
Integer j=new Integer(0);
System.out.println(i==j);//true
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态...
    梦工厂阅读 58,034评论 38 277
  • 学习和使用java已经有4年多了,反省一下,太多关注了实际的应用层面,对某些基础的东西没有特别理解透彻。好记性不如...
    破东风CAFEBABY阅读 1,662评论 4 26
  • java常量池是一个经久不衰的话题,也是面试官的最爱,题目花样百出。理论jvm虚拟内存分布: ** 程序计...
    Java红茶阅读 337评论 0 4
  • java常量池是一个经久不衰的话题,也是面试官的最爱,题目花样百出,小菜早就对常量池有所耳闻,这次好好总结一下。 ...
    堤岸小跑阅读 307评论 0 0
  • 10月13日,智联招聘最新发布了《2015年秋季贵阳雇主需求与白领人才供给报告》,公布了贵阳秋季求职十大高薪行业,...
    贵州新目标阅读 627评论 0 2