先看一个简单的例子:


public class TestInteger { public static void main(String[] args) {
System.out.println("----20----");
littleNum();
System.out.println();
System.out.println("----250----");
bigNum();
} public static void littleNum(){
Integer i1 = 20; //1
Integer i2 = 20; //2
Integer i3 = new Integer(20); //3
Integer i4 = new Integer(20); //4
int i5 = 20; //5
System.out.println("i1==i2?: " + (i1 == i2));
System.out.println("i1==i3?: " + (i1 == i3));
System.out.println("i1==i5?: " + (i1 == i5));
System.out.println("i3==i4?: " + (i3 == i4));
System.out.println("i3==i5?: " + (i3 == i5));
} public static void bigNum(){
Integer i1 = 250; //1
Integer i2 = 250; //2
Integer i3 = new Integer(250); //3
Integer i4 = new Integer(250); //4
int i5 = 250; //5
System.out.println("i1==i2?: " + (i1 == i2));
System.out.println("i1==i3?: " + (i1 == i3));
System.out.println("i1==i5?: " + (i1 == i5));
System.out.println("i3==i4?: " + (i3 == i4));
System.out.println("i3==i5?: " + (i3 == i5));
} }

打印结果是:

----20----
i1==i2?: true
i1==i3?: false
i1==i5?: true
i3==i4?: false
i3==i5?: true ----250----
i1==i2?: false
i1==i3?: false
i1==i5?: true
i3==i4?: false
i3==i5?: true

结果好像跟想象中的不太一样,这里涉及到自动拆装箱的问题。

自动装箱和拆箱从Java 1.5开始引入,自动装箱与拆箱的机制可以让我们在Java的变量赋值或者是方法调用等情况下使用原始类型或者对象类型更加简单直接。

自动装箱就是Java自动将基本类型值转换成对应包装类的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。

这里的拆装箱是由编译器自动完成的,所以就称作为自动装箱和拆箱。

基本类型包括byte,short,char,int,long,float,double和boolean对应的封装类为Byte,Short,Character,Integer,Long,Float,Double,Boolean。

自动装箱时编译器调用valueOf()将基本类型值转换成对象,同时自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成节本类型值。

我们都知道对于 == 而言,在比较基本数据类型的时候是比较的它们的值,而在比较引用数据类型的时候是比较它们的内存地址。

所以,对于 i1==i3?: false 以及 i3==i4?: false 而言,后者是通过new产生的一个新对象,内存地址不同,结果为false;

而对于i1==i5?: true以及i3==i5?: true而言,i5是基本数据类型,==比较的是它们的值,所以结果都是true;

说到 == 的比较,这里要补充一下,Integer类里面重写了equals()方法,所以equals()方法比较的是值

说完了 == 的比较,下面来说一下i1==i2 为什么对于20和对250的结果不一样。

这里就牵涉到Integer的缓存,在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。

在Integer的源码中,有一个IntegerCache的内部类,实现了Integer的缓存:

/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. During VM initialization the
* getAndRemoveCacheProperties method may be used to get and remove any system
* properites that configure the cache size. At this time, the size of the
* cache may be controlled by the -XX:AutoBoxCacheMax=<size> option.
*/ // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)
private static String integerCacheHighPropValue; static void getAndRemoveCacheProperties() {
if (!sun.misc.VM.isBooted()) {
Properties props = System.getProperties();
integerCacheHighPropValue =
(String)props.remove("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null)
System.setProperties(props); // remove from system props
}
} private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[]; static {
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low));
}
high = h; cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
} private IntegerCache() {}
}

这里可以看到,一般而言对于 -128-127之间的Integer类型,IntegerCache内部使用了一个Integer的数组来保存它们,而在Integer的valueOf()方法中,调用了IntegerCache的这个缓存池。

valueOf()的源代码如下:

    /**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
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);
}

回到之前的问题上来,在-128-127之间的Integer类型直接从缓存里面取,而在这之外的Integer类型会通过new创建一个新的对象。

这种 Integer 缓存策略仅在自动装箱的时候有用,使用构造器创建的 Integer 对象不能被缓存。因为在自动装箱过程中会调用Integer的valueOf()方法。

回头细看一下IntegerCache这个类的javadoc,Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。

这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。

实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。

除了Integer之外,其他的一些包装类型也存在类似的缓存机制,比如Short型:

    private static class ShortCache {
private ShortCache(){} static final Short cache[] = new Short[-(-128) + 127 + 1]; static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i - 128));
}
}

和Integer不同的是,Short的范围是固定在-128-127不变的。

Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。

Integer的缓存和自动拆装箱的更多相关文章

  1. Java的自动拆装箱与Integer的缓存机制

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10832303.html 一:基本类型与包装类型     我们知道,Java有8大基本数据类型,4整2浮1符1 ...

  2. Integer缓存机制-基本数据类型和包装类型-自动拆装箱

    Integer缓存机制 总结: 1.jdk1.5对Integer新增了缓存机制,范围在-128-127(这个范围的整数值使用频率最高)内的自动装箱返回的是缓存对象,不会new新的对象,所以只要在缓存范 ...

  3. 自动拆装箱(int,Integer)

    包装类型Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个 ...

  4. java中的自动拆装箱与缓存(Java核心技术阅读笔记)

    最近在读<深入理解java核心技术>,对于里面比较重要的知识点做一个记录! 众所周知,Java是一个面向对象的语言,而java中的基本数据类型却不是面向对象的!为了解决这个问题,Java为 ...

  5. 《java入门第一季》之Integer类和自动拆装箱概述

    / * int 仅仅是一个基本类型.int有对应的类类型,那就是Integer.  * 为了对基本数据类型进行更多的操作,更方便的操作,Java就针对每一种基本数据类型提供了对应的类类型--包装类类型 ...

  6. 关于java的自动拆装箱若干细节问题

    一.首先需要了解的几个前提: 1.自动装箱过程是通过调用valueOf方法实现的(如Integer.valueOf(10)),而拆箱过程是通过调用包装器的 xxxValue方法实现的(如Integer ...

  7. Java的自动拆/装箱

    作者:Alvin 关键字:语法糖 类 对象 参考 Java 中的语法糖 语法糖--这一篇全了解 浅谈 Integer 类 什么是Java中的自动拆装箱 深入剖析Java中的装箱和拆箱 前言 我们知道, ...

  8. 一文读懂什么是Java中的自动拆装箱

    基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型.它们是我们编程中使用最频繁的类型. Java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为 ...

  9. Java基础(二) 基本类型数据类型、包装类及自动拆装箱

    我们知道基本数据类型包括byte, short, int, long, float, double, char, boolean,对应的包装类分别是Byte, Short, Integer, Long ...

随机推荐

  1. Matlab中imshow()函数的使用

    imread() 返回的图像类型是uint8类型, 这时用imshow显示图像的时候, imshow会认为输入矩阵的范围在0-255, 如果imshow的参数为double类型的,那么imshow认为 ...

  2. nodejs API笔记

    一.URL 涉及到的方法 1.parse():解析地址 2.format():生成地址 3.resolve(from,to):组合成地址 举例说明: url.parse('http://baidu.c ...

  3. linux内核地址mapping

    linux内核采用页式存储管理,虚拟地址空间划分成固定大小的页面,由MMU(memory manager unit)在运行时将virtual address mapping to (或者说是变化成)某 ...

  4. 客户端接口AGENDA

    日程 周二上午:完善客户端功能.接口定义. 周二下午:助教审查客户端代码.审查完成之后将发布接口定义. 提示 总之谢谢大家的支持.我们会尽量降低交互难度,让各位亲把精力专注于算法设计上面. 可以使用任 ...

  5. Tomcat中配置JNDI数据源

    准备工作: Tomcat版本:tomcat6.0以上 下例中均使用MySQL数据库 将对应数据源的jar包和MySQL的驱动包拷贝至tomcat的lib文件夹下 一.全局数据源 1步骤一:配置 在to ...

  6. Spring EL Lists, Maps example

    In this article, we show you how to use Spring EL to get value from Map and List. Actually, the way ...

  7. WebForm中如何防止页面刷新,后退导致的重复提交

    当用户按下浏览器中的 F5 键刷新当前页面时,对这一过程进行检测所需的操作步骤.页面刷新是浏览器对特定用户操作(按 F5 键或单击"刷新"工具栏按钮)的响应.页面刷新操作是浏览器内 ...

  8. HDU 3577 Fast Arrangement (线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3577 题意不好理解,给你数字k表示这里车最多同时坐k个人,然后有q个询问,每个询问是每个人的上车和下车 ...

  9. hibernate id生成器配置

    1.uuid配置 <id name="tomdId" type="java.lang.String"> <column name=" ...

  10. 关于session更新的问题

    最近在学习用ssh框架做一个实习生招聘系统,已经做了大半.今天突然想到一个问题,在登录的时候我把用户的所有信息放到session中去,那么我不同用户同时登录的时候session中的信息是否会被覆盖掉( ...