java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
下面小编就为大家带来一篇细数 java 中 Long 与 Integer 比较容易犯的错误总结小编觉得挺不错的, 现在就分享给大家, 也给大家做个参考一起跟随小编过来看看吧
今天使用 findbugs 扫描项目后发现很多高危漏洞, 其中非常常见的一个是比较两个 Long 或 Integer 时直接使用的 == 来比较 其实这样是错误的
因为 Long 与 Ineger 都是包装类型, 是对象 而不是普通类型 long 与 int , 所以它们在比较时必须都应该用 equals, 或者先使用 longValue()或 intValue()方法来得到他们的基本类型的值然后使用 == 比较也是可以的
但是有一种特殊情况, 其实 Long 与 Integer 都将 -128~127 这些对象缓存了 可以看看 Long 类型源码里面有一个 LongCache 类, 代码如下:
- private static class LongCache {
- private LongCache(){}
- static final Long cache[] = new Long[-(-128) + 127 + 1];
- static {
- for(int i = 0; i < cache.length; i++)
- cache[i] = new Long(i - 128);
- }
- }
先看看这个例子:
- public class Test05 {
- public static void main(String[] args) {
- Long a = 5L;
- Long b = 5L;
- System.out.println("a == b ?" + (a == b));
- Long c = 129L;
- Long d = 129L;
- System.out.println("c == d ?" + (c == d));
- }
- }
打印的结果是:
- a == b ? true
- c == d ? false
原因
首先来看看 Long a = 5L ; 它是如何将一个基本类型 long 包装成一个对象 Long 的
可以写一个测试类, 然后反编译一下, 看看 java 它是如何解析 Long a = 5L 这样一条命令的
测试类如下:
- public class Test06 {
- Long l = 3L;
- }
然后使用 javap -verbose Test06 就能看到反编译的结果了, 下面是输出的部分:
- {
- java.lang.Long l;
- public com.spring.test.Test06();
- Code:
- Stack=3, Locals=1, Args_size=1
- 0: aload_0
- 1: invokespecial #10; //Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: ldc2_w #12; //long 3l
- 8: invokestatic #14; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
- 11: putfield #20; //Field l:Ljava/lang/Long;
- 14: return
- LineNumberTable:
- line 3: 0
- line 5: 4
- line 3: 14
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 15 0 this Lcom/spring/test/Test06;
- }
从 Code 中的 8 可以看出调用了 Long 的一个类方法 Long.valueOf(Long) , 所以可以得到的结论是 Long a = 5L 实际上等于 Long a = Long.valueOf(5) ;
然后再看看 Long.valueOf()方法是如何定义的:
- public static Long valueOf(long l) {
- final int offset = 128;
- if (l >= -128 && l <= 127) { // will cache
- return LongCache.cache[(int) l + offset];
- }
- return new Long(l);
- }
一目了然, 会先判断基本类型的值如果在 - 128~127 之间, 就会直接从 LongCache 里面取出缓存的对象返回, 否则就 new 一个新的 Long 对象返回
现在就不难理解 Test05 程序执行得到的结果了, 因为 a 与 b 等于 5, 在 - 127~128 之内, 所以都是直接从 LongCache 里面返回的一个 Long 对象, 所以他们在使用 == 比较的时候, 就是相等的(对于对象类型来说,== 比较的是两个对象的引用指向堆中的地址) , 而 c 与 d 等于 129, 不在 - 127~128 之间, 所以他们他们是分别 new 出来的两个新的 Long 对象, 使用 == 来比较自然是不相等的了
Long 重写了 equals 方法:
- public boolean equals(Object obj) {
- if (obj instanceof Long) {
- return value == ((Long) obj).longValue();
- }
- return false;
- }
它是先通过. longValue()方法获取 Long 对象的基本类型 long 的值之后再做比较的
所以对于 Integer 与 Long 的比较, 最好是使用 equals 来比较才能确保得到我们想要的结果
Integer 与 Long 一样, 这里就不举例了
来源: http://www.phperz.com/article/18/0213/358708.html