ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

[Java]_[初级]_[装箱和拆箱的陷阱-不要使用==进行包裹类型wrapper class比较]

2021-09-14 18:33:27  阅读:167  来源: 互联网

标签:拆箱 Java ie1 ie5 ie4 wrapper int print Integer


场景

  1. 在使用JavaInteger进行算术运算时, 偶尔发现使用 == 比较运算符两个int值一样的前提下结果是false, 什么原因?

说明

  1. JDK5已经开始提供装箱(autoboxing)和拆箱(auto-unboxing)的功能,目的是可以在原始数据类型和包裹(wrapper)类型之间方便转换,也能方便进行算术运算. 这样就不需要频繁的调用Integer.intValue()Integer.valueOf()来转换类型了.

  2. 另一个作用就是在集合类里, 泛型类型必须是引用类型的,因此是没有List<int>这种写法,只能是List<Integer> 或者 List<Object>等。一些需要Object作为参数的方法,在传递int类型时会自动转换为Integer类型, 还是比较方便的.

  3. 使用Integer进行算术和比较运算时,它会自动拆箱为int类型进行计算。但是有一个==比较运算符是所有Object都支持的,如果进行Integer == Integer比较,那么实际上是调用了Object.equals进行比较,并不是算术比较,这个要注意了。再次强调, 不要对两个类型都是Integer进行==比较运算, 其中一个Integer转换为int再进行比较两两==比较。 其他的比较运算符, 如>=等会先拆箱为int比较,是正确的.

以下的两个Integer类型进行==比较是可以的.

print("ie4 == ie5",ie4.compareTo(ie5) == 0);
print("ie4.intValue() == ie5",ie4.intValue() == ie5);
print("ie4+0 == ie5", (ie4+0) == ie5);
print("(int)ie4 == ie5", (int)ie4 == ie5); 
  1. 至于如果Integer值在[-128,127]区间[2]使用的静态缓冲区也可以进行==比较。但是没用, 既然进行比较就不知道它的具体值,所以不用考虑这种比较,还是老老实实手动转换为int进行==比较.

JDK进行的valueOf实现:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  1. 除了Integer类型,还有以下的包裹类型支持对应的原始类型:
Primitive typeWrapper class
booleanBoolean
byteByte
charCharacter
floatFloat
intInteger
longLong
shortShort
doubleDouble

例子

  1. 以下是Integerint进行装箱的各种情况:

AutoBoxingTest

package com.example.string;

import org.junit.jupiter.api.Test;



public class AutoBoxingTest {
    
    public static<T> void print(String key,T t){
        System.out.println(key +" : "+t);
    }

    
    public static<T> void add_1(Integer input){
        input += 1;
    }

    public static void add_2(int input){
        print("add_2",input); // 调用泛型方法自动装箱为Integer类型.
    }

    @Test
    public void testInteger(){

        //情况1. Integer可用于算术运算符, 遇到算术运算符自动拆箱为int类型.
        Integer ie1 = Integer.valueOf(10); // 创建不可变Integer对象.
        print("ie1",ie1); // 10
        print("ie1 id",System.identityHashCode(ie1));
        ie1 += 100; 
        ie1 = ie1 +10;
        print("ie1",ie1); // 120
        print("ie1 id",System.identityHashCode(ie1)); // 注意: 对象ID已经改变,ie1指向的不是原来的Integer对象了.


        //情况2: Integer作为参数是值传递的.
        int i1 = ie1; // 可赋值给原始变量, 自动拆箱.
        print("i1",i1); // 120 值未发生变化 
        add_1(ie1); // 可传递给原始变量的参数. 
        print("ie1",ie1); // 120 值未发生变化

        // 情况3: Integer可传递给int参数的方法。
        add_2(ie1); // 120

        // 情况4: int传递给Integer参数方法时自动装箱.
        add_1(i1);
        print("ie1",ie1); // 120
        
        // 情况5: int赋值给Integer变量时自动装箱.
        Integer ie2 = new Integer(120);
        print("ie2",ie2); // 120
        Integer ie3 = 120;
        print("ie3",ie3); // 120
        
        //  情况6: 不允许Integer和int之间使用比较运算符.
        print("ie2 > ie1",(ie2 >= ie1)); //true
        print("ie2 == ie1",(ie2 == ie1)); // false
        print("ie3 == ie1",(ie3 == ie1)); // true -128<= ie <= 127 使用的是常量池的对象,因此比较是相同的.
            
        Integer ie4 = 290;
        Integer ie5 = 290;    
        print("ie4 == ie5",(ie4 == ie5));  // false > 127, 创建了新对象。  
        print("ie4 >= ie5",(ie4 >= ie5)); // true 自动拆箱为int比较
        // 使用compareTo来判断是否相等.
        print("ie4 == ie5",ie4.compareTo(ie5) == 0); // true
        // 结论, 不要使用 == 符号来比较两个Integer类型数据.
        // integer和int做运算时,integer会自动拆箱为int类型,结果也为int类型, 之后int和integer类型比较,integer类型又会自动拆箱.
        print("ie4+0 == ie5", (ie4+0) == ie5); // true
        print("(int)ie4 == ie5", (int)ie4 == ie5); // true int强制转换和integer赋值给int一样,会拆箱
        print("ie4.intValue() == ie5",ie4.intValue() == ie5); // true
        
        // 非wrap类型使用比较符只能是 ==.    
        String s1 = "1"; // 常量存储区
        String s2 = new String("1"); // 非常量池
        //if(s1 > s1) // 非Wrapper 类型使用非==比较运算符编译报错.
        print("s1 == s2",(s1 == s2));  //false 会转换为使用equals()比较, 所以不一样
            
        // List<int> tt; // 编译错误
    }
    
}

输出

参考

  1. Autoboxing and Unboxing

  2. Why is 128128 false but 127127 is true when comparing Integer wrappers in Java?

  3. Java 装箱和拆箱 128陷阱问题

标签:拆箱,Java,ie1,ie5,ie4,wrapper,int,print,Integer
来源: https://blog.csdn.net/infoworld/article/details/120293544

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有