【JAVA】条件 a == (Integer) 1 && a == (Integer) 2有可能为true吗?

 

一、废话

先看看这个代码

            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。

 

 

全部评论
更多博客请移步https://blog.csdn.net/qq_33591903
点赞 回复
分享
发布于 2020-03-24 16:42

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务