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 ...
随机推荐
- My implementation of AVL tree
C++实现的avl平衡树 #include <stdlib.h> #include <time.h> #include <string.h> #include &l ...
- 区间DP+next求循环节 uva 6876
// 区间DP+next求循环节 uva 6876 // 题意:化简字符串 并表示出来 // 思路:dp[i][j]表示 i到j的最小长度 // 分成两部分 再求一个循环节 #include < ...
- Using Apache Maven
Apache Maven是一个软件项目管理的综合工具(management and comprehension tool).可以将WAR文件部署到App Engine中.为了加快部署的速度,App E ...
- 时间都去哪了?——安卓GTD工具
GTD是英文Getting Things Done的缩写,是一种行为管理的方法,也是David Allen写的一本书的书名. GTD的主要原则在于一个人需要通过记录的方式把头脑中的各种任务移出来.通过 ...
- scanf,sscanf利用format跳过干扰的空格
scanf,sscanf利用format跳过干扰的空格 用了一点时间做读取配置部分的代码,希望一次记录上读取N个数据, 希望读取的格式就是一个IP地址加上端口号,希望把IP地址读取到4个短整数里面,端 ...
- homework6-更加简单的题目
又把时间搞错了 以为这次要写客户端程序的博客 没想到这次是“怎么吃” 言归正传 cnblog上面有很多技术博客 http://perhaps.cnblogs.com/archive/2005/08/0 ...
- C:移位运算符
1在向右移位时,空出的位是由0填充,还是由符号位的副本填充? 如果被移位的对象是无符号数,那么空出的位将被0填充.如果被位移的对象是有符号数,那么C语言实现既可以用0填充空出的位,也可以用符号位的副本 ...
- ajax乱码问题 服务端 客户端 两种的解决方案--转载
今天弄了一天的Ajax中文乱码问题,Ajax的乱码问题分为两种: 1. JavaScript输出的中文乱码, 比如:alert("中文乱码测试"); 2. 这第二种就是Ajax从服 ...
- ssi整合报错org.apache.struts2.convention.ConventionsServiceImpl.determineResultPath(ConventionsServiceImpl.java:100)
java.lang.RuntimeException: Invalid action class configuration that references an unknown class name ...
- 高扩展的基于NIO的服务器架构
当你考虑写一个扩展性良好的基于Java的服务器时,相信你会毫不犹豫地使用Java的NIO包.为了确保你的服务器能够健壮.稳定地运行,你可能会花大量的时间阅读博客和教程来了解线程同步的NIO selec ...