做客户端“忘记密码”功能有bug,今天调试时,发现了原因:

功能模块中有一段:

1
2
3
4
if(userpo.getId() != Long.valueOf(uid)){
throw new VerifyException("mobile have been binded for uid=" + uid ,
AppCode.VERIFY_MOBILE_IS_BIND);
}

问题就出在两个Long型对象的比较。

情景:

userpo.getId()返回一个Long型对象,值是10027;
Long.valueOf(uid)返回一个Long型对象,值也是10027;

通过 != 运算,值是 true ,实际期待的是 false

解决方案:

以上代码应该改成:

1
2
3
4
if(!userpo.getId().equals(Long.valueOf(uid))){
throw new VerifyException("mobile have been binded for uid=" + uid ,
AppCode.VERIFY_MOBILE_IS_BIND);
}

userpo.getId().equals(Long.valueOf(uid)) 返回 true , 所以在java中 对象比较一般推荐使用 equals 方法或者compareTo方法

疑问:

当初代码肯定是通过测试的,那当初是为什么会通过测试?

思考:

值得注意的是,最初学java时,印象中Integer和Long类型的对象有使用过 == 、!= 这样来比较,结果好像也对过。

其实确实有些情况使用 == 、!= 这样来比较 也对。

例如我写了一个测试类测试Integer和Long类型对象的比较:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
public static void main(String[] args) {
Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println("a==b:" + (a==b)); //很明显false
Integer c = 129;
Integer d = 129;
System.out.println("c==d:" + (c==d)); //false
Integer e = 127;
Integer f = 127;
System.out.println("e==f:" + (e==f));//true
Long h = 128L;
Long g = 128L;
System.out.println("h==g:" + (h==g));//false
System.out.println("h.equals(g):" + h.equals(g));//true
System.out.println("h.compareTo(g):" + h.compareTo(g));// 0
Long k = 127L;
Long m = 127L;
System.out.println("k==m:" + (k==m));//true
System.out.println("k.equals(m):" + k.equals(m));//true
System.out.println("k.compareTo(m):" + k.compareTo(m));// 0
}
}

执行结果:

1
2
3
4
5
6
7
8
9
a==b:false
c==d:false
e==f:true
h==g:false
h.equals(g):true
h.compareTo(g):0
k==m:true
k.equals(m):true
k.compareTo(m):0

分析:

查看Integer源代码后发现Integer有个内部类IntegerCache,它维护了一个Integer数组cache[] ,长度为256,还有一个静态块

1
2
3
4
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}

很明显这个静态块已经默认认创建出了-128~127 的 Integer 数据。
Integer在创建对象时,若值在(-128到127)范围内,则直接从缓冲区中取,若超过该范围则创建新对象,所以在-128到127范围内Integer对象值相同时,对象 == 返回true

Long对象同理。