- 浏览: 26117 次
- 性别:
- 来自: 广州
文章分类
最新评论
本文将介绍 Java 中 Integer 缓存的相关知识。这是 Java 5 中引入的一个有助于节省内存、提高性能的特性。
首先看一个使用 Integer 的示例代码,展示了 Integer 的缓存行为。接着我们将学习这种实现的原因和目的。
你可以先猜猜下面 Java 程序的输出结果。很明显,这里有一些小陷阱,这也是我们写这篇文章的原因。
/**
* 测试Integer的缓存 IntegerCache.cache
*/
private static void testIntegerCache() {
System.out.println("---int---");
int a = 127, b = 127;
System.out.println(a == b); //true
a = 128;
b = 128;
System.out.println(a == b); //true
System.out.println("---Integer---");
Integer aa = 127, bb = 127;
System.out.println(aa == bb); //true
aa = 128;
bb = 128;
System.out.println(aa == bb); //false
System.out.println(aa.equals(bb)); //true
}
执行结果就如同上面的那样,我就不贴图来展示啦,我把原文的例子给换成自己的了。
在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。
上面的规则适用于整数区间 -128 到 +127。
这种 Integer 缓存策略仅在自动装箱(autoboxing)的时候有用,使用构造器创建的 Integer 对象不能被缓存。
Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法
Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood
现在我们知道了 JDK 源码中对应实现的部分在哪里了。我们来看看 valueOf 的源码。下面是
JDK 1.8.0 build 25 中的代码。
/**
* 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.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
在创建新的 Integer 对象之前会先在 IntegerCache.cache (是个Integer类型的数组)中查找。有一个专门的 Java 类来负责 Integer 的缓存。
IntegerCache 类
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. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
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;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。 缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。
实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。是什么原因选择这个 -128 到 127 这个范围呢?因为这个范围的整数值是使用最广泛的。 在程序中第一次使用 Integer 的时候也需要一定的额外时间来初始化这个缓存。
Java 语言规范中的缓存行为
在 Boxing Conversion 部分的Java语言规范(JLS)规定如下:
如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1这个估计是版本号吧),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。
其他缓存的对象
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
有 ByteCache 用于缓存 Byte 对象
有 ShortCache 用于缓存 Short 对象
有 LongCache 用于缓存 Long 对象
有 CharacterCache 用于缓存 Character 对象
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。
原文:http://javapapers.com/java/java-integer-cache/
首先看一个使用 Integer 的示例代码,展示了 Integer 的缓存行为。接着我们将学习这种实现的原因和目的。
你可以先猜猜下面 Java 程序的输出结果。很明显,这里有一些小陷阱,这也是我们写这篇文章的原因。
/**
* 测试Integer的缓存 IntegerCache.cache
*/
private static void testIntegerCache() {
System.out.println("---int---");
int a = 127, b = 127;
System.out.println(a == b); //true
a = 128;
b = 128;
System.out.println(a == b); //true
System.out.println("---Integer---");
Integer aa = 127, bb = 127;
System.out.println(aa == bb); //true
aa = 128;
bb = 128;
System.out.println(aa == bb); //false
System.out.println(aa.equals(bb)); //true
}
执行结果就如同上面的那样,我就不贴图来展示啦,我把原文的例子给换成自己的了。
在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。
上面的规则适用于整数区间 -128 到 +127。
这种 Integer 缓存策略仅在自动装箱(autoboxing)的时候有用,使用构造器创建的 Integer 对象不能被缓存。
Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法
Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood
现在我们知道了 JDK 源码中对应实现的部分在哪里了。我们来看看 valueOf 的源码。下面是
JDK 1.8.0 build 25 中的代码。
/**
* 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.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
在创建新的 Integer 对象之前会先在 IntegerCache.cache (是个Integer类型的数组)中查找。有一个专门的 Java 类来负责 Integer 的缓存。
IntegerCache 类
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. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
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;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。 缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。
实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。是什么原因选择这个 -128 到 127 这个范围呢?因为这个范围的整数值是使用最广泛的。 在程序中第一次使用 Integer 的时候也需要一定的额外时间来初始化这个缓存。
Java 语言规范中的缓存行为
在 Boxing Conversion 部分的Java语言规范(JLS)规定如下:
如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1这个估计是版本号吧),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。
其他缓存的对象
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
有 ByteCache 用于缓存 Byte 对象
有 ShortCache 用于缓存 Short 对象
有 LongCache 用于缓存 Long 对象
有 CharacterCache 用于缓存 Character 对象
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。
原文:http://javapapers.com/java/java-integer-cache/
发表评论
-
Spring Junit 读取WEB-INF下的配置文件
2018-01-25 10:31 640测试环境:Spring3.0.5 + Junit4.8.1 ... -
转:有多少人在滥用 service+serviceImpl,又有多少人在误用myBatis
2018-01-25 10:40 5014被滥用的service+serviceImpl JA ... -
@Autowired和new的区别
2018-01-25 10:35 2826@Autowired相当于setter,在注入之前,对象已经实 ... -
Spring、使用注解方式装配对象(@Resource、@Autowired)
2018-01-25 10:33 662首先,引入注解所使用的Jar包 :common-anno ... -
阿里巴巴java开发手册 1.2
2017-07-07 20:28 655前言 《阿里巴巴 Java 开 ... -
深入解析---MySQL查询优化之explain
2017-07-06 19:33 464在分析查询性能时,考虑EXPLAIN关键字同样很管用。EXP ... -
转: Java之CountDownLatch使用
2017-07-04 16:23 3991、类介绍 一个同步辅助类,在完成一组正在其他线程中执行 ... -
SimpleDateFormat线程安全重现与解决
2017-07-04 14:59 704一. 为什么SimpleDateFormat不是线程安全的 ... -
Thread.join()方法详解
2017-07-04 11:15 861API: join public final ... -
hashMap优化
2017-06-30 15:51 4941 集合初始化时,指定集合初始值大小。 说明:Ha ... -
jdk7 Collections.sort()引发的IllegalArgumentException
2017-06-30 15:26 1613一 IllegalArgumentException的重 ... -
java内部类:如何使用
2017-06-29 16:57 529一 定义:放在一个类的内部的类我们就叫内部类。 二、 ... -
ArrayList循环遍历并删除元素的常见陷阱
2017-06-29 11:22 364在工作和学习中,经常碰到删除ArrayList里面的某个元 ... -
eclipse快速创建标准maven管理的javaEE、web项目
2017-06-28 11:10 4181 先安装 eclipse maven 插件的安 ... -
@WebServlet注解配置问题记录
2017-06-23 10:34 2329@WebServlet 该注解用于在Web应用中定义Serv ... -
性能优化之ArrayList
2017-06-22 14:25 422ArrayListTest 写道 package cn.c ... -
LinkedList和ArrayList的使用及性能分析
2017-06-22 10:54 420转自http://www.jb51.net/arti ... -
ArrayList源码分析
2017-06-22 10:36 486ArrayList就是传说中的动态数组,就是Array的 ...
相关推荐
作者以易于理解的方式深入揭示了java虚拟机的内部工作原理,深入理解这些内容,将对读者更快速地编写更高效的程序大有裨益! 本书共分20章,第1-4章解释了java虚拟机的体系结构,包括java栈、堆、方法区、执行...
【标题】:深入理解Java内存使用与优化:从代码到Java堆 【描述】:本文旨在帮助Java开发者深入了解从编写代码到Java堆的内存管理过程,以便更好地优化应用程序的内存使用。通过分析Java代码中的内存开销,以及讨论...
在实际开发中,还需要考虑数据的级联操作(CascadeType)、懒加载(Lazy Fetching)以及缓存策略等高级特性。同时,为了保持数据一致性,还需要理解并合理使用`@PrePersist`, `@PostPersist`, `@PreUpdate`, `@Post...
### JAVA常见异常BUG详解 #### 一、Java.lang....开发者应该深入理解这些异常的原因,并采取有效措施来预防它们的发生。在实际开发过程中,良好的编码习惯和严格的测试流程对于减少这类异常至关重要。
查看`Integer`的源码可以帮助我们更深入地理解其内部机制,比如`Integer.valueOf()`方法如何实现值缓存,以及`Integer`对象的比较操作是如何进行的。 6. **扩展讨论**: - 自动装箱/拆箱发生的时间:这些操作发生...
Java 是一种广泛使用的编程语言,尤其在企业级应用和服务器端开发中占据主导地位。面试时,面试官通常会从多个方面考察候选...Java的面试涵盖范围广泛,深入理解每个领域并能灵活运用是成为优秀Java开发者的必备条件。
JDK(Java Development Kit)是Java开发工具包,它提供了Java开发和运行环境,包括JRE(Java Runtime Environment),以及用于编译Java源码的编译器Javac和其他调试工具。JRE仅提供运行Java程序所需的环境,如果...
本文将深入探讨Java的一些值得注意的细节,帮助你避免常见陷阱,提升代码质量。 1. **自动装箱与拆箱**:Java中的`Integer`等包装类提供了自动装箱和拆箱功能,方便了开发者操作。但需要注意,虽然在基本类型和包装...
该书分为基础篇、进阶篇、高级篇、架构篇和拓展篇五个部分,覆盖了Java编程的多个层面,包括Java虚拟机(JVM)的深入理解、Java基础语法、并发编程、网络编程以及最新的Java技术动态。书中还推荐了一系列的参考书籍...
此外,面试题还可能涉及多线程的并发控制(如synchronized, volatile, Lock等)、集合框架(ArrayList, LinkedList, HashMap等的原理与使用)、SpringBoot框架的配置与使用、MySQL的索引优化、Redis的缓存策略以及...
Java面试八股文是准备Java面试的关键资源,涵盖了广泛的Java技术领域,包括基础概念、框架、并发、JVM以及软技能。...准备面试时,不仅要掌握这些基础概念,还需要深入理解并能灵活应用到实际问题中。
4. **优化数据库操作**:通过源码,学习如何提高数据库读写性能,如批量操作、缓存策略等。 五、源码实践 实际开发中,你可以: 1. **扩展SQLJet功能**:根据需求,自定义SQLJet的行为,比如增加新的数据类型或函数...
4. **理解并发模型**:深入理解Java的并发模型(如volatile关键字的作用机制、原子操作的实现原理等),有助于更好地设计并行算法和数据结构。 ### 总结 通过对上述知识点的理解和实践,开发者可以在编写Java应用...
Java 架构师在面试过程中会面临一系列深入且全面的问题,涵盖从基础知识到高级概念的广泛领域。以下是一些基于给定标题和描述的关键知识点详解: 1. **Java 语言特点**: - **简单易学**:Java 语法简洁,易于理解...
在Java编程语言中,处理大整数(Big Integer)是一项挑战,尤其是在进行高精度运算时。标题中的"java_sqr(big_int)"暗示我们要讨论的是如何在Java中对大整数执行平方根(square root)操作。这个压缩包中的"java_sqr...
【Java基础】 1. JDK与JRE的区别: JDK(Java Development Kit)...以上仅是部分Java面试题及知识点的概述,每个话题都包含了大量的细节和实践技巧,深入学习和理解这些知识点对于成为一名优秀的Java开发者至关重要。
Redis的使用,如缓存策略、数据结构和操作命令。 **十六、JVM** 了解JVM内存模型,垃圾回收机制,性能调优等。 **十七、数据结构与算法** 熟练掌握链表、树、堆、图等数据结构,以及排序、搜索等基础算法,有助...