`

【JDK优化】 Integer 自动打包机制的优化

阅读更多

我们首先来看一段代码:

Integer i=100;
Integer j=100;
System.out.println(i==j);  //true
Integer i=200;
Integer j=200;
System.out.println(i==j);  //false

 

差不多的两段代码,怎么结果完全不同呢。我们分两步来说明这个问题:

 

首先 Integer i=100; 编译器会自动将int类型常数100包装成Interger,采用的是Integer.valueOf(100); 这个方法。

 

然后我们看看valueOf(int)这个方法的源代码:

 /*
  * 返回一个表示指定的 int 值的 Integer 实例。如果不需要新的 Integer 实例,则
  * 通常应优先使用该方法,而不是构造方法 Integer(int),因为该方法有可能通过
  * 缓存经常请求的值而显著提高空间和时间性能。 
  * @param  i an <code>int</code> value.
  * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
  * @since  1.5
  */
public static Integer valueOf(int i) {
      final int offset = 128;
      if (i >= -128 && i <= 127) { // must cache 
	    return IntegerCache.cache[i + offset];
     }
     return new Integer(i);
}

 /*
  * IntegerCache内部类
  * 其中cache[]数组用于存放从-128到127一共256个整数
  */
private static class IntegerCache {
	private IntegerCache(){}

	static final Integer cache[] = new Integer[-(-128) + 127 + 1];

	static {
	    for(int i = 0; i < cache.length; i++)
		cache[i] = new Integer(i - 128);
	}
}

 

原来如此,当-128=<i<=127的时候,返回的是IntegerCache中的数组的值;当 i>127 或 i<-128 时,返回的是Integer类对象。 这就好解释:

 

Integer i=100;
Integer j=100;
System.out.println(i==j);  //(1)

此时的 i=IntegerCache.cache[228],因此 Integer引用i中存储的是cache数组第228号元素的地址。同理j也是同一个cache数组的第228号元素的地址(因为cache是Integer的静态数组,只有一个)。i==j比较的是引用地址,因此相等。

Integer i=200;
Integer j=200;
System.out.println(i==j);  //(2)

此时的 i=new Integer(200);  同样j=new Integer(200) 。两次都在堆中开辟了Integer的对象。i 和 j 中存储的堆得对象地址是完全不同的。i==j 自然不相等了。

 

那么这样做有什么意义呢? 我们来看看API的解释:

返回一个表示指定的 int 值的 Integer 实例。如果不需要新的 Integer 实例,
则通常应优先使用该方法,而不是构造方法 Integer(int),因为该方法有可能
通过缓存经常请求的值而显著提高空间和时间性能。 

假如我们在编程时大量需要值为100的Integer对象,如果只能通过new来创建的话。是不是需要在堆中开辟大量值一样的Integer对象呢!这是相当不划算的。既然如此,Java中的字符串常量池的应用是不是可以提醒我们点什么呢?是的,IntegerCache.cache就相当于这样一个字符串常量池。 当我们需要Integer i=100的时候,直接从cache中取出第[100+128]号元素的地址赋值引用i,再次需要Integer j=100时,还是直接去这个地址赋给j ..... 是不是省去了再堆中不停的创建对象的代价了(空间,时间上的消耗都很大)。

 

 

 

 

 

分享到:
评论
18 楼 sarin 2010-03-15  
也是比值和比地址的问题
17 楼 captmjc 2010-03-15  
一般能确保非空的情况下,还是int比较安心一点。
16 楼 robertliudeqiang 2010-03-14  
呵呵,的确是陷阱。
15 楼 Heart.X.Raid 2010-03-14  
呵呵,我也是在CSDN上面看别人的发帖才去研究一下的。其实JDK源码里面有很多有意义的东西,大师们写的好东西研究多久都是有好处的。因为他们是大师。
14 楼 laoshifu 2010-03-14  
一般来说我们不会去看全部的JDK的实现源码,有问题的时候才去深究的,楼主的这种做法很好,省去了我们不少的时间。我平时为了性能问题,有时候也会去看JDK的源码,如果大家研究一点,然后在论坛上分享讨论,应该进步更快。
13 楼 linliangyi2007 2010-03-14  
虽然楼主的做法不遵从对象法则,但有时候打破常规还是很有意义的,哈哈,赞一个
12 楼 mercyblitz 2010-03-14  
skzr.org 写道
对于==和Object的equals
对于对象而言 一个是引用比较,一个是对象(逻辑)比较
反正比较对象我都是使用:equals不会用==的



看清楚这个帖子说什么,不要说这些不相干的东西!
11 楼 mercyblitz 2010-03-14  
wujiazhao88 写道
除了考虑性能外还要考虑空间啊,建议看下Integer类的源码你就知道了



貌似你没有看清楚上面说的!
10 楼 kjj 2010-03-13  
既然是对象,楼主第一种i==j的比较方法实际上是算了空子,很多基础都讲得很清楚嘛,比较对象要用equals 而非 ==
9 楼 victorlin23 2010-03-13  
Integer i=100;  
Integer j=100;  
System.out.println(i.intValue()==j.intValue() );  //(1)  
 
Integer i=200;  
Integer j=200;  
System.out.println(i.intValue() ==j.intValue() );  //(2)

如果比较值是否相等请用:Integer的intValue()
8 楼 finux 2010-03-13  
不错。不过,比较对象还是推荐用equals
7 楼 skzr.org 2010-03-13  
对于==和Object的equals
对于对象而言 一个是引用比较,一个是对象(逻辑)比较
反正比较对象我都是使用:equals不会用==的
6 楼 wujiazhao88 2010-03-13  
除了考虑性能外还要考虑空间啊,建议看下Integer类的源码你就知道了
5 楼 Heart.X.Raid 2010-03-13  
mercyblitz 写道


为了性能提升,在JVM实施优化的话,那么应该保存多少个这样实例呢,1万还是?
目前SUN JDK的实现是256个这样的缓存,这是一种折中的方法,实际上,很多实体ID很有可能超过127,并且重复出现。



说的对,我也对256的缓存的设置有异议。设置256个有什么依据呢?这个问题确实有待Java的设计者来解释。但我觉得,如果需要创建的整数对象较少的时候。最好不要用valueOf这种方法,毕竟要创建256个Integer对象的缓存空间。但如果数据量大,而且重复较多的情况下,还是可以考虑的,毕竟优化一点是一点吗? 至于如何选择要根据程序员自己的经验了。
4 楼 mercyblitz 2010-03-13  
Heart.X.Raid 写道
mercyblitz 写道
这个东西为了性能考虑,但是这种性能提升也有问题~



不是很理解,能不能详细一点。为什么这种性能提升是有问题的??



为了性能提升,在JVM实施优化的话,那么应该保存多少个这样实例呢,1万还是?
目前SUN JDK的实现是256个这样的缓存,这是一种折中的方法,实际上,很多实体ID很有可能超过127,并且重复出现。

3 楼 Heart.X.Raid 2010-03-13  
mercyblitz 写道
这个东西为了性能考虑,但是这种性能提升也有问题~



不是很理解,能不能详细一点。为什么这种性能提升是有问题的??
2 楼 C_J 2010-03-13  
因为实际上我们的编码会比较  i.equals(j),而非i==j,这种性能提升未尝不可?
1 楼 mercyblitz 2010-03-13  
这个东西为了性能考虑,但是这种性能提升也有问题~

相关推荐

    Jenkins 支持jdk1.7+jdk1.8打包.zip

    Jenkins 支持jdk1.7+jdk1.8打包,包括兼容组件、maven包,JDK建议用:jdk-8u11-linux-x64、jdk-7u80-linux-x64。 安装前将plugins放到/root/.jenkins/路径下,再启动Jenkins,首次启动跳过安装插件步骤,直接进入...

    Tomcat、JDK优化配置

    本篇文章将深入探讨如何对Tomcat和JDK进行优化配置,以提高应用性能。 首先,我们来讨论Tomcat的优化。`catalina.sh`是Tomcat的启动脚本,它包含了启动、停止和运行Tomcat的各种选项。以下是一些关键的优化策略: ...

    tomcat JDK打包部署

    总结来说,"Tomcat JDK打包部署"涵盖的知识点包括但不限于:JDK的安装与配置、Tomcat服务器的搭建与管理、项目构建工具的使用(Maven或Gradle)、应用的打包成`.war`文件、Tomcat的自动化部署、源代码的管理和版本...

    exe4j jdk1.7 jar打包exe工具

    【exe4j jdk1.7 - jar打包exe工具】是一种专为Java应用程序设计的工具,它允许开发者将Java的jar文件转换成Windows平台下的可执行文件(exe)。这个过程通常被称为“打包”,目的是使非Java环境的用户也能直接运行...

    java打包,可以将jdk集成进去

    Java打包技术是将Java应用程序和必要的运行环境(如JDK)整合到一起,使得用户无需安装额外的Java环境即可运行程序。在Java开发过程中,为了方便分发和部署,我们通常会将应用及其依赖打包成一个可执行的格式,比如...

    集成jdk+mysql+tomcat+web项目打包成rpm

    在IT行业中,软件分发和部署是至关...对于初学者,这不仅是一个学习RPM打包的好实践,也是了解系统集成和自动化部署的关键步骤。记住,良好的文档和测试是成功打包的关键,因为它们确保了软件包的稳定性和用户友好性。

    JDK环境变量自动配置

    可以自动配置jdk环境变量及自动切换不懂版本的jdk,方便多套开发环境切换

    spoon 环境的1.8jdk 和1.8jre 打包了

    标题中的"spoon 环境的1.8jdk 和1.8jre 打包了"表明这是一个关于Spoon工具的环境配置包,其中包含了Java的两个关键组件:Java Development Kit (JDK) 1.8版本和Java Runtime Environment (JRE) 1.8版本。Spoon是一款...

    Jdk6解压打包版本

    3. **Swing增强**:JDK 6对Swing组件进行了大量优化,例如`JSplitPane`的改进,使得布局管理更加灵活。还添加了`JTabbedPane`的滚动支持和`JTable`的行选择模式。 4. **Web服务支持**:Java EE 6的一部分,JDK 6...

    Jdk7解压打包版本

    8. **改进的编译器(javac)**:Javac在JDK 7中得到了优化,能够更好地处理类型推断和错误报告,提高了编译效率。 9. **并发工具类增强**:并发工具类库(java.util.concurrent)中增加了Fork/Join框架,用于执行...

    Mac下JDK7重新打包后的安装包

    重新打包了Mac下的JDK7的安装包,避免了提示macbook安装低版本的jdk,提示“Oracle 的 Java 要求 Mac OS X 10.7.3 或更高版本”的问题

    jdk64位打包下载

    JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛的Java SDK。JDK 是整个Java的核心,包括了Java运行环境、Java工具和Java基础类库。JDK是学好Java的...

    nsis打包Tomcat_JDK_MYSQL

    自己测试通过用nsis实现打包Tomcat JDK MYSQL及应用的程序包;本人上传了“ webapp_Tomcat_JDK_MYSQL.nsi ”有需要的可以下载参考;

    JDK1.8自动脚本安装

    本篇文章将详细讲解如何使用JDK1.8的自动脚本进行安装,以及这个过程中的关键知识点。 1. **自动脚本安装的优势**: - 自动脚本安装JDK1.8简化了传统手动配置的复杂步骤,包括下载、解压和设置环境变量等。 - 不...

    jdk1.6jar包

    1. **改进的性能**:JDK 1.6通过优化JVM和类加载机制,提升了运行时的性能,尤其是对于大规模应用和并发处理。 2. **增强的内存管理**:包括更高效的垃圾回收机制,如并行垃圾回收和CMS(Concurrent Mark Sweep)...

    Android自动打包、签名、优化、上传ANT脚本

    ### Android自动打包、签名、优化、上传ANT脚本详解 #### 一、概述 随着移动互联网的发展,Android应用开发越来越受到开发者的重视。为了提高开发效率、减少人为错误,自动化工具变得尤为重要。其中,利用ANT脚本...

    JDK14之jpackage打包命令

    1.前提:已安装JDK14,可以到jdk官网下载,或加QQ群835259695,快速免费下载 2.不说没用的直接上jdk14环境下的jpackage命令,打开cmd窗口输入:jpackage -h 得到如下内容: F:&gt;jpackage -h WARNING: Using incubator...

    json-lib-2.4-jdk15.jar全部JAR打包直接用

    然而,对于那些不使用这些工具或者没有自动管理依赖的项目,直接使用`json-lib-2.4-jdk15.jar`的全部JAR打包方式可以避免配置繁琐的依赖关系,简化了开发流程。 `json-lib`库提供了多种Java对象与JSON之间的转换...

    JDK11安装包,JDK11安装包

    JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11...

    dubbo-master 打包 jdk1.8

    dubbo-master 打包 jdk1.8dubbo-master 打dubbo-master 打包 jdk1.8包 jdk1.8dubbo-master 打包 jdk1.8dubbo-master 打包 jdk1.8dubbo-master 打包 jdk1.8dubbo-master 打dubbo-master 打包 jdk1.8包 jdk1.8dubbo-...

Global site tag (gtag.js) - Google Analytics