本文将介绍 Java 中 Integer 的缓存相关知识. 这是在 Java 5 中引入的一个有助于节省内存, 提高性能的功能. 首先看一个使用 Integer 的示例代码, 从中学习其缓存行为. 接着我们将为为什么这么实现以及他到底是如何实现的. 你能猜出下面的的 Java 程序的输出结果吗. 如果你的结果和真正结果不一样, 那么你就要好好看看本文了.
- package com.javapapers.java;
- public class JavaIntegerCache {
- public static void main(String... strings) {
- 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");
- }
- }
我们普遍认为上面的两个判断的结果都是假的. 虽然比较的值是相等的, 但是由于比较的是对象, 而对象的引用不一样, 所以会认为两个如果判断都是错误的. 在 Java 的中,== 比较的是对象应用, 而 equals 比较的的英文值. 所以, 在这个例子中, 不同的对象有不同的引用, 所以在进行比较的时候都将返回错误. 奇怪的是, 这里两个类似的, 如果条件判断返回不同的布尔值.
上面这段代码真正的输出结果:
- integer1 == integer2
- integer3 != integer4
Java 的中整数的缓存实现
在 Java 5 中, 在 Integer 的操作上引入了一个新功能来节省内存和提高性能. 整型对象通过使用相同的对象引用实现了缓存和重用.
适用于整数值区间 - 128 至 + 127.
只适用于自动装箱. 使用构造函数创建对象不适用.
的 Java 的编译器把基本数据类型自动转换成封装类对象的过程叫做自动装箱, 使用相当于 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);
- }
在创建对象之前先从 IntegerCache.cache 中寻找. 如果没找到才使用新新建对象.
IntegerCache 类
IntegerCache 是整数中类定义的一个 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=} 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 可以通过 - XX:AutoBoxCacheMax=size 修改. 缓存通过一个用于循环实现. 从低到高并创建尽可能多的整数并存储在一个整数数组中. 这个缓存会在整数类第一次被使用的时候被初始化出来. 以后, 就可以使用缓存中包含的实例对象, 而不是创建一个新的实例(在自动装箱的情况下).
实际上这个功能在 Java 5 中引入的时候, 范围是固定的 - 128 至 + 127. 后来在 Java 6 中, 可以通过 java.lang.Integer.IntegerCache.high 设置最大值. 这使我们可以根据应用程序的实际情况灵活地调整来提高性能. 到底是什么原因选择这个 - 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 包装成一个和 b 两个对象时, 可以直接使用一个 == b 判断一个和 b 的值是否相等.
其他缓存的对象
这种缓存行为不仅适用于整数对象. 我们针对所有的整数类型的类都有类似的缓存机制.
有 ByteCache 用于缓存字节对象
有 ShortCache 用于缓存短对象
有 LongCache 用于缓存长对象
有 CharacterCache 用于缓存字对象
Byte,Short,Long 有固定范围:-128 到 127 对于 Character, 范围是 0 到 127. 除了 Integer 以外, 这个范围都不能改变.
来源: http://www.bubuko.com/infodetail-3169765.html