[Java]_[初级]_[装箱和拆箱的陷阱-不要使用==进行包裹类型wrapper class比较]
Posted infoworld
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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; // 编译错误
输出
参考
以上是关于[Java]_[初级]_[装箱和拆箱的陷阱-不要使用==进行包裹类型wrapper class比较]的主要内容,如果未能解决你的问题,请参考以下文章