[Java]_[初级]_[装箱和拆箱的陷阱-不要使用==进行包裹类型wrapper class比较]
2021/9/14 20:05:14
本文主要是介绍[Java]_[初级]_[装箱和拆箱的陷阱-不要使用==进行包裹类型wrapper class比较],对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
场景
- 在使用
Java
的Integer
进行算术运算时, 偶尔发现使用==
比较运算符两个int
值一样的前提下结果是false
, 什么原因?
说明
-
JDK5
已经开始提供装箱(autoboxing
)和拆箱(auto-unboxing
)的功能,目的是可以在原始数据类型和包裹(wrapper
)类型之间方便转换,也能方便进行算术运算. 这样就不需要频繁的调用Integer.intValue()
或Integer.valueOf()
来转换类型了. -
另一个作用就是在集合类里, 泛型类型必须是引用类型的,因此是没有
List<int>
这种写法,只能是List<Integer>
或者List<Object>
等。一些需要Object
作为参数的方法,在传递int
类型时会自动转换为Integer
类型, 还是比较方便的. -
使用
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);
- 至于如果
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); }
- 除了
Integer
类型,还有以下的包裹类型支持对应的原始类型:
Primitive type | Wrapper class |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
float | Float |
int | Integer |
long | Long |
short | Short |
double | Double |
例子
- 以下是
Integer
和int
进行装箱的各种情况:
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; // 编译错误 } }
输出
参考
-
Autoboxing and Unboxing
-
Why is 128128 false but 127127 is true when comparing Integer wrappers in Java?
-
Java 装箱和拆箱 128陷阱问题
这篇关于[Java]_[初级]_[装箱和拆箱的陷阱-不要使用==进行包裹类型wrapper class比较]的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-28MQ底层原理资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:入门与初级用户指南
- 2024-11-28MQ消息队列资料入门教程
- 2024-11-28MQ消息队列资料:新手入门详解
- 2024-11-28MQ消息中间件资料详解与应用教程
- 2024-11-28MQ消息中间件资料入门教程
- 2024-11-28MQ源码资料详解与入门教程
- 2024-11-28MQ源码资料入门教程
- 2024-11-28RocketMQ底层原理资料详解