一、废话
先看看这个代码
int a = 1;
if (a == (Integer) 1 && a == (Integer) 2) {
System.out.println("true");
}
在我的idea中,该段代码被标黄了,提示我Condition is always false.
乍一看,确实为false啊,怎么可能a的值即为1,又为2?
可是仔细想一想,这段代码和(a==1&&a==2)还是有很大区别的,至少(a==1&&a==2)肯定为false。
但是这里将基本数据类型转为包装类,转化后的值可不可能是一个值呢?
二、代码
废话不多说,先上输出为true的代码
package com.yang.test;
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) {
Class cache = Integer.class.getDeclaredClasses()[0];
Field c;
try {
c = cache.getDeclaredField("cache");
c.setAccessible(true);
Integer[] array = (Integer[]) c.get(cache);
array[130] = array[129];
int a = 1;
if (a == (Integer) 1 && a == (Integer) 2) {
System.out.println("true");
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
该段代码确实可以输出为true,真的好神奇啊,到底是怎么实现的呢?
三、实现过程
1、首先,使用
Class cache = Integer.class.getDeclaredClasses()[0];
拿到Integer类中某个内部类,看了Integer类,这个类中只有一个静态内部类,那就是IntegerCache类。
2、接着,使用
c = cache.getDeclaredField("cache");
c.setAccessible(true);
Integer[] array = (Integer[]) c.get(cache);
拿到IntegerCache中的cache变量,并强制转化为Integer数组。
3、这是最重要的一步
array[130] = array[129];
array[129]的值到底是多少?先看一下这个内部类的源码
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
private IntegerCache() {
}
static {
int h = 127;
//读取配置参数-Djava.lang.Integer.IntegerCache.high的值,一般我们不会去配置,因此直接跳过这段代码,直接看high=h
String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
int i;
if (integerCacheHighPropValue != null) {
try {
i = Integer.parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
h = Math.min(i, 2147483518);
} catch (NumberFormatException var4) {
}
}
high = h;
//这里的high为127
cache = new Integer[high - -128 + 1];
//cache=new Integer[256];
i = -128;
for(int k = 0; k < cache.length; ++k) {
cache[k] = new Integer(i++);
}
//cache[0]=new Inteher(-128);
//cache[129]=new Inteher(1);
//cache[130]=new Inteher(2);
//cache[255]=new Integer(127);
assert high >= 127;
}
}
现在可以知道,这个内部类中的cache数组,cache[129]=1,cache[130]=2
说到现在,那这个内部类到底干啥的呢?
(Integer) 1,这一句话,将会执行自动装箱操作,相当于调用Integer.valueOf方法
先看integer.valueOf源码
public static Integer valueOf(int i) {
return i >= -128 && i <= Integer.IntegerCache.high ?
Integer.IntegerCache.cache[i + 128] : new Integer(i);
}
此时,如果i属于[-128,127]区间时,将会返回cache数组中对应的值,例如i=0时,返回cache[128],这个值等于0,否则的话,重新创建一个Integer实例。将[-128,127]缓存在Integer内部类IntegerCache里的数组中,有需要直接取,这样的举措能带来效率上的提升。
那么,我们利用反射,修改IntegerCache类里变量cache数组的值,将array[130] = array[129],而array[129]=1。
那么此时将1和2装箱成Integer时,会调用Integer.valueOf方法,(Integer)1返回cache[129],而(Integer)2返回cache(130),
然后a==(Integer)1,基本类型和包装类型比较时,包装类型会自动执行拆箱工作,也就是调用Integer.intValue()方法,该方法返回Integer构造方法中传入的value值。关于装箱与拆箱,可以参考我的另外一篇文章【JAVA】谈谈拆箱与装箱
现在,已经很显而易见了,a现在等于1,(Integer)1等于cache[129],也就是等于new Integer(1),拆箱后等于1
(Integer)2等于cache[130],在我们利用反射修改数组的值后,此时cache[130]也等于new Integer(1),拆箱后还是等于1
因此,上例中确实可以返回true。