java整型缓存
来源:互联网 发布:golang select 编辑:程序博客网 时间:2024/05/16 18:31
缓存大家应该都听说过,像计算机中的缓存用于提高计算机性能,浏览器的缓存会在下一次访问该网站时一定程度上提高访问速度。通常缓存是用空间换时间,那么java中既节省了内存又提高了效率的缓存大家是否知道呢?这里就向大家介绍介绍”Java Integer Cache”。
这篇博客翻译自《Java Integer Cache》,限于本人英文水平,翻译可能有些偏差,请大家见谅
这篇Java文章是介绍整型缓存的。这个特性是在Java 5时为了节省内存、提高效率而引入Java的。让我们先看一段简单的使用了Integer
并且展示了整型缓存行为的代码。从这里,我们可以学习整型缓存是如何实现的,以及为什么这样实现。你可以猜测一下下面这段Java程序的输出结果。显然这里的输出有些问题,这也是我写这篇博客的原因。
Integer integer1 = 3;Integer integer2 = 3;if (integer1 == integer2) System.out.println("integer1 == integer2");else System.out.println("integer1 != integer2");Integer integer3 = 300;Integer integer4 = 300;if (integer3 == integer4) System.out.println("integer3 == integer4");else System.out.println("integer3 != integer4");
通常,我们会认为这两个表达式都会返回false
。虽然比较的两个值是一样的,但是比较的两个对象却应该是两个不同引用。如果你是初学者,那么请注意,在Java中==
比较对象的引用,而equals()
通常是比较对象的值。所以在这个例子中,比较的两个对象有不同的引用,他们应该返回false
。奇怪的是,他们的结果并不相同,两个相似的if表达式返回了不同的boolean
值.
让我们看看上面那段Java程序的输出
integer1 == integer2
integer3 != integer4
Java整型缓存实现
在Java 5中,一个新特性被引入为了节省内存和改善整数类型的对象的处理性能。整数对象会在内部缓存并通过相同的引用对象重用
- 这个特性被用于在-128到+127(包含)之间的
Integer
对象 Integer
缓存只有在自动装箱时才会使用。如果一个Integer
对象是通过构造函数构建的,那么将不会使用已经缓存的引用。
由Java编译器自动将原始数据类型转换为相应的Java包装类的操称为自动装箱。这相当于调用valueOf
方式:
Integer a = 10; // 自动装箱Integer b = Integer.valueOf(10); // 效果同自动装箱
所以现在我们知道这个缓存应该是在Java类库源代码中实现的。让我们看看Java类库中的valueOf
方法的源码(JAVA_HOME/src.zip解压)。以下的代码是Java JDK 1.8.0 build 40中的。
/** * 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
中查表寻找。IntegerCache
是一个用于维护Integer
类型缓存的类。
IntegerCache
类
IntegerCache
是Integer
类的private static
内联类。让我们看看这个类的源码。里面有相当好的文档注释,这会给我们很多信息。
/** * 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可以使用VM的启动参数-XX:AutoBoxCacheMax=size
修改。所以,缓存的内容是在一个for
循环中创建的。它从最小值循环到最大值,并且创建对应Integer
变量,之后存储在一个名为cache的Integer
数组中。这些缓存在第一次使用Integer
类时创建。之后,这些被缓存起来的实例会在自动装箱时用来代替创建新的实例。
实际上,在Java 5引入这个特性时,缓存的范围是固定的:-128到127。在Java 6以后,这个范围的最大值被映射到了java.lang.Integer.IntegerCache.high
属性上,并且允许我们通过VM参数设置最大值。这允许我们根据使用的情况灵活调整性能。那么选择缓存的数字范围为-128到127的原因是什么呢?这是因为,这个范围被认为是整数使用最频繁的范围。当然,在程序中第一次使用Integer
类时,需要额外的时间缓存这些实例。
Java语言规范中的Cache规定
在Java Language Specification(JLS)的装箱转换部分有如下声明:
如果p是在-128到127(包含)之间的整型字面值,或者boolean字面值
true
、false
,或者是在'\u0000'
到'\u007f'
之间的字符字面值。那么,对于p经过两次装箱操作形成的两个对象a和b,a==b总是成立的
以上语句确保值在-128到127之间的对象引用是相同的.同时还可以根据这句话得到这些信息:
理论上,我们可以缓存所有的原始类型值。但实际上,使用现有的技术是不可能实现的。上边的规则是一个比较现实的实现,要求一定范围的原始类型类装箱后总是获得相同的引用。规则没有向程序员保证其他值会的得到相同或者不同的的引用。这允许(而不是要求)共享一些或者全部其他基本类型值的引用。注意长整类型的字面量可以共享引用,当然这不是必须的 。
这会保证在大多数情况下,行为总是可靠、可预测的,同时没有太多的性能损失,特别是对于运行在小型设备上的程序。更少的内存的使用是可能实现的,比如:缓存所有的char
和short
类型的值,以及在-32K到32K的范围内的int
和long
类型的值。
其他缓存对象
缓存行为并不仅仅适用于Integer
对象,在所有的整型类型类上都有相似的缓存机制。
- ByteCache
用于缓存Byte
对象
- ShortCache
用于缓存Short
对象
- LongCache
用于缓存Long
对象
- CharacterCache
用于缓存Character
对象 Byte
、Short
、Long
有固定的缓存范围,比如在-128和127(包含)之间的值。对于Character
类,缓存的范围为0到127(包含),除了Integer
外,其他类型的缓存范围不能通过启动参数修改。
翻译于2015/04/13
- java整型缓存
- Java整型缓存
- Java中整型的缓存机制
- Java中整型的缓存机制
- 深入理解java 整型数, Integer的缓存
- java整型
- java整型
- Python的整型缓存机制
- JAVA字符串转整型
- Java的整型
- java 字符串转为整型
- 14.JAVA整型变量
- java整型类型
- java-基础-1.1 整型
- Java 之 整型比较
- java-对整型数组排序
- java 字符串转化整型问题
- Java解惑之长整型
- StoryBoard+AutoLayout实战开发小技巧
- pg_restore数据库恢复指令
- 任正非接班人李一男离开华为时给属下的忠告
- 第2章 第3题
- aix无法创建2G以上大文件的问题
- java整型缓存
- Mysql命令行导入sql数据
- ubuntu12.04 安装配置jdk1.7
- AngularJS 数据双向绑定揭秘
- 不会是不是应该的
- Android中Cursor类的概念和用法
- SDUT 3185 Lexicography(排列问题(不会))
- phpword - 生成word的php类库相关问题总结
- 面对对象之继承