Integer的缓存和自动拆装箱
先看一个简单的例子:
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的缓存和自动拆装箱的更多相关文章
- Java的自动拆装箱与Integer的缓存机制
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10832303.html 一:基本类型与包装类型 我们知道,Java有8大基本数据类型,4整2浮1符1 ...
- Integer缓存机制-基本数据类型和包装类型-自动拆装箱
Integer缓存机制 总结: 1.jdk1.5对Integer新增了缓存机制,范围在-128-127(这个范围的整数值使用频率最高)内的自动装箱返回的是缓存对象,不会new新的对象,所以只要在缓存范 ...
- 自动拆装箱(int,Integer)
包装类型Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个 ...
- java中的自动拆装箱与缓存(Java核心技术阅读笔记)
最近在读<深入理解java核心技术>,对于里面比较重要的知识点做一个记录! 众所周知,Java是一个面向对象的语言,而java中的基本数据类型却不是面向对象的!为了解决这个问题,Java为 ...
- 《java入门第一季》之Integer类和自动拆装箱概述
/ * int 仅仅是一个基本类型.int有对应的类类型,那就是Integer. * 为了对基本数据类型进行更多的操作,更方便的操作,Java就针对每一种基本数据类型提供了对应的类类型--包装类类型 ...
- 关于java的自动拆装箱若干细节问题
一.首先需要了解的几个前提: 1.自动装箱过程是通过调用valueOf方法实现的(如Integer.valueOf(10)),而拆箱过程是通过调用包装器的 xxxValue方法实现的(如Integer ...
- Java的自动拆/装箱
作者:Alvin 关键字:语法糖 类 对象 参考 Java 中的语法糖 语法糖--这一篇全了解 浅谈 Integer 类 什么是Java中的自动拆装箱 深入剖析Java中的装箱和拆箱 前言 我们知道, ...
- 一文读懂什么是Java中的自动拆装箱
基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型.它们是我们编程中使用最频繁的类型. Java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为 ...
- Java基础(二) 基本类型数据类型、包装类及自动拆装箱
我们知道基本数据类型包括byte, short, int, long, float, double, char, boolean,对应的包装类分别是Byte, Short, Integer, Long ...
随机推荐
- [JLOI2013]地形生成
JLOI2013过了好长时间,才写第四题.. 第一问比较好想. 第二问我想到了n^3次方的做法,但是数据....于是没敢写,然后上网查了一下题解,居然是O(n^3)过的,数据这么弱... /* * P ...
- delphi 单例模式实现
unit Unit2; interface uses System.SysUtils; type { TSingle } TSingle = class(TObject) private FStr: ...
- c函数调用过程原理及函数栈帧分析
转载自地址:http://blog.csdn.net/zsy2020314/article/details/9429707 今天突然想分析一下函数在相互调用过程中栈帧的变化,还是想尽量以比 ...
- Web Service学习之一:Web Service原理
一.定义 Web Service 不是框架也不是技术 而是解决远程调用.跨平台调用.跨语言调用问题的一种规范. 二.应用1.同一个公司新.旧系统的整合:比如CRM系统与OA.客服系统相互调用2.不同公 ...
- Win7下使Users数据与程序分离
大家知道,数据是用户最大的财富,但Windows系统默认的模式是将所有软件都安装在C盘,在Windows XP时代,数据文件夹会放在Document And Setting 目录下,在Win7时代,数 ...
- HDU 4901 The Romantic Hero (计数DP)
The Romantic Hero 题目链接: http://acm.hust.edu.cn/vjudge/contest/121349#problem/E Description There is ...
- labview 中activex的初步使用方法
1.在前面板放置一个activex容器 2.插入activex控件 3.百度找到这个activex控件的属性和方法介绍 4.程序框图中右键activex控件,创建xxx类的方法或者xxx的属性:act ...
- sublime text2 用ctags插件实现方法定位
sublime text2 用ctags插件实现方法定位(转) 我们用sublime几乎都会首先安装这个插件,这个插件是管理插件的功能,先安装它,再安装其他插件就方便了. 点击sublime的菜单栏 ...
- window 下cygwin开启了后来又关闭了
特征: ssh localhost 出现port 27 拒绝访问等 系统日志记录信息: 事件 ID ( 0 )的描述(在资源( sshd )中)无法找到.本地计算机可能没有必要的注册信息或消息 DLL ...
- 算法之旅,直奔<algorithm>之十七 find_first_of
find_first_of(vs2010) 引言 这是我学习总结 <algorithm>的第十七篇,find_first_of是匹配的一个函数.<algorithm>是c++的 ...