想必大部分学过java的人都应该做过这种题目:

 public class Test {
public static void main(String[] args) {
//第一个字符串
String s1="hello"; //第二个字符串
String s2="hello"; //比较s1和s2是否相同
System.out.println(s1==s2); /**
* 修改变量
*/ s1=new String("hello"); s2=new String("hello"); //再次比较s1和s2是否相同
System.out.println(s1==s2);
}
};

最后的结果如图:

图一

对于这个结果,我相信没有人有异议!因为第一组是依靠常量池的结果,即String s1=“hello”时实际会在内存中栈的常量池中创建一个字符串常量“hello”对象,当String s2=“hello”时,因为常量池中已经存在,所以s2会直接指向同一个”hello“对象,也就是s1和s2对象的地址值是一致的,此时的String就有点类似与基本数据类型,所以用“==”来比较的时候,值为“true”。

而如果String s1=new String("hello")时,s1在堆中开辟出新的内存空间存放“hello”值,同理,s2也会在堆中重新开辟空间存放“hello”值,s1和s2所指向的值的地址不同,用“==”来比较的时候自然是不同的,值为“false”。

但不知道有多少人做过下面这道题目呢?

修改一下上题中的变量类型为Integer。

 package action;

 public class Test {
public static void main(String[] args) {
//第一个数值
Integer s1=127; //第二个数值
Integer s2=127; //比较s1和s2是否相同
System.out.println(s1==s2); /**
* 修改变量
*/ s1=128; s2=128; //再次比较s1和s2是否相同
System.out.println(s1==s2);
}
};

你的答案会是什么呢?


结果图如下:

图二

是不是有点出乎你的意料呢?

从原理上来说,Integer和String类型都属于引用类型,那么最后的结果应该和String类型的比较一致,而且就算Integer类型的没有常量池技术那么这两次的结果也应该一致啊,毕竟只是相差1而已!

这就是我这篇博客要说的java常量池的小陷阱了!

java中的基本数据类型的包装类有6种实现了常量池技术,他们分别是:Byte , Short,Integer,Long ,Characher ,Boolean。Double和Float没有实现,佐证如下图:

图三

直接定义常量是会报错的(这个佐证其实有点不靠谱,如果有谁知道,麻烦告诉一声,谢谢!)

这5种包装类在常量池的实现上与String有点区别,以Integer为例,当有Integer i=127时,实际上发生了如下操作:

Integer i=Integer.valueOf(127)

Integer.valueOf()方法基于减少对象创建次数和节省内存的考虑,缓存了[-128,127]之间的数字。此数字范围内传参则直接返回缓存中的对象。在此之外,直接new出来.

而在上述所说的6种有常量池技术的包装类中,除了Boolean以外,其他的值都不能超过  127  (小于或者等于) ,超过127常量池就不予自动创建对象,这时包装类就和普通的引用类型没有区别了。

关于常量池的详细介绍,可以借鉴这篇博客(我也是从中得到原因的):

http://www.cnblogs.com/qinqinmeiren/archive/2011/07/19/2151683.html

关于Integer.valueOf()可以参考这篇:

http://blog.csdn.net/randyjiawenjie/article/details/7603427

java常量池中基本数据类型包装类的小陷阱的更多相关文章

  1. 【转载】Java常量池

    本篇随笔为转载,原贴地址:Java常量池理解与总结. (其实Java的常量池有点像C++中的存储字符串常量的常量存储区). 一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法 ...

  2. java常量池

    Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new.newarray. anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放.堆是由垃圾回 ...

  3. Java基础知识强化103:Java常量池理解与总结

    一.相关概念 1. 什么是常量 用final修饰的成员变量表示常量,值一旦给定就无法改变! final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. 2. Class文件中的 ...

  4. java常量池概念

    在class文件中,“常量池”是最复杂也最值得关注的内容. Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int.long等等)和对象型(如Stri ...

  5. java常量池詳解

    一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池在Clas ...

  6. java虚拟机学习-Java常量池理解与总结(13-2)

    一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池在Clas ...

  7. Java常量池的理解

    1.常量池的好处常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享.例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中.(1)节省内存空间:常量池中所有相同的字符串常 ...

  8. [转]java常量池理解总结

    一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池在Clas ...

  9. java 常量池

    在jvm规范中,每个类型都有自己的常量池.常量池是某类型所用常量的一个有序集合,包括直接常量(基本类型,String)和对其他类型.字段.方法的符号引用.之所以是符号引用而不是像c语言那样,编译时直接 ...

随机推荐

  1. 7.spark共享变量

    spark共享变量 1 Why Apache Spark 2 关于Apache Spark 3 如何安装Apache Spark 4 Apache Spark的工作原理 5 spark弹性分布式数据集 ...

  2. java利用接口和适配器进行完全解耦--参考《thinking in java》

    一.当使用父子类来实现以下东西时,其实是用了向上转型,这段代码的确简单了很多,复用性也很好,但是我们会发现Apply.process()和Processor类耦合过紧,其实apply.process( ...

  3. Python零基础学习系列之一--初识计算机!

    1-1.计算机概念: Computer: 原指专门负责计算的人,后来演变成特指计算设备,译为"计算机" 计算机的概念: 计算机是能够根据一组指令操作数据的机器. A compute ...

  4. akoj-1267-独木舟上的荡漾

    独木舟上的荡漾 Time Limit:1000MS  Memory Limit:65536K Total Submit:76 Accepted:44 Description 进行一次独木舟的旅行活动, ...

  5. Linux Command Line(I): Beginner

    考試月終於暫告一段落,終於有時間回歸Linux 的懷抱.不知怎的,在VMware Workstation 12 上登入Ubuntu後總是blue screen,明明昨天用terminal 也沒有事啊真 ...

  6. ECMAScript6-let与const命令详解

    前言 <ECMAScript入门>是一本开源的JavaScript语言教程,全面介绍ECMAScript6新引入的语法特性. let和const命令,是第一章开始介绍,也是比较基础的知识. ...

  7. 轻松学JVM(四)——垃圾回收算法

    我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. stop the world 在介绍垃圾 ...

  8. 爬取西刺ip代理池

    好久没更新博客啦~,今天来更新一篇利用爬虫爬取西刺的代理池的小代码 先说下需求,我们都是用python写一段小代码去爬取自己所需要的信息,这是可取的,但是,有一些网站呢,对我们的网络爬虫做了一些限制, ...

  9. 学习笔记TF049:TensorFlow 模型存储加载、队列线程、加载数据、自定义操作

    生成检查点文件(chekpoint file),扩展名.ckpt,tf.train.Saver对象调用Saver.save()生成.包含权重和其他程序定义变量,不包含图结构.另一程序使用,需要重新创建 ...

  10. 漫谈ELK在大数据运维中的应用

    漫谈ELK在大数据运维中的应用 圈子里关于大数据.云计算相关文章和讨论是越来越多,愈演愈烈.行业内企业也争前恐后,群雄逐鹿.而在大数据时代的运维挑站问题也就日渐突出,任重而道远了.众所周知,大数据平台 ...