简述
看到这个问题是不是觉得很神奇,其实只要利用一点Java的语法特性就能解决问题。
1、解决思路:
Java专家组发现,Integer对象初始化的大部分数据介于-128~127之间,因此Integer对小数据(-128~127)预置了缓存,以此来提升大部分情况下实例化一个Integer的性能。其解决办法是,在jvm初始化的时候,数据-128~127之间的数字便被缓存到了本地内存中,如果初始化-128~127之间的数字,会直接从内存中取出,不需要新建一个对象,而这个数据被缓存在Integer的内部类IntegerCache中。所以我们通过获取Integer内部类IntegerCache,也就是缓存-128~127的类,并将索引为129(也就是1)的对象赋值给130(2)、131(3),此时当我们从Integer中去取值的时候就会发现1 == 2 == 3。
2、Integer内部类IntegerCache源码
源码示例:
/** * IntegerCache缓存了-128~127 */ 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() {} }
3、具体实现
代码示例:
package com.lizba.p3; import java.lang.reflect.Field; /** * <p> * a == 1 && a == 2 && a == 3示例代码 * </p > * * @Author: Liziba * @Date: 2021/6/3 17:19 */ public class IntegerTest { public static void main(String[] args){ try { Class<?>[] declaredClasses = Integer.class.getDeclaredClasses(); Class<?> integerCache = declaredClasses[0]; Field f = integerCache.getDeclaredField("cache"); f.setAccessible(true); Integer[] cache = (Integer[]) f.get(integerCache); System.out.println(cache[129]); System.out.println(cache[130]); System.out.println(cache[131]); cache[130] = cache[129]; cache[131] = cache[129]; Integer a = 1; // true if (a == (Integer) 1 && a == (Integer) 2 && a == (Integer) 3) { System.out.println(true); } // true if (a == Integer.valueOf(1) && a == Integer.valueOf(2) && a == Integer.valueOf(3)) { System.out.println(true); } // 无输出 if (a == new Integer(1) && a == new Integer(2) && a == new Integer(3)) { System.out.println(true); } System.out.println(cache[129]); System.out.println(cache[130]); System.out.println(cache[131]); } catch (Exception e) { e.printStackTrace(); } } }
5、总结
这些知识点都是用来考验一个开发者对JDK特性的熟练程度和平时的积累,有时候要是问上了也是有用的,或者也给我们在实际开发中做数据预热来提升服务的性能,带来了一定的思考价值。