第五周_T-细节之下无魔法"45".equals(Long l)

44 阅读2分钟

题目背景:输出 true OR false 「基于 JDK8」

long id=45;
System.out.println("45".equals(id));

给答案

输出 false

猜想

一眼看到题目:肯定输出 true 啊,这还用想?结果自然打脸

  • long 类型的缓存问题?
  • long 类型的自动转换问题?

验证:

  1. 我使用的是 equals :在 Java 中是比较值的;== :在 Java 才是比较内存地址的(可能会有问题)。所以使用 equals 是不会出问题的。
  2. 自动转换问题:反编译 .class 文件,如下
long id=45;
System.out.println("45".equals(Long.ValueOf(id)));

"45" 是一个字符串 String 类型。Java 中有基本数据类型,其他都是对象类型,而 long 属于基本数据类型,需要转换为对象数据类型:Long 。那么即是:Long.ValueOf(id) 返回 Long 对象类型。

再看 String#equals 源码:

 public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        return (anObject instanceof String aString)
                && (!COMPACT_STRINGS || this.coder == aString.coder)
                && StringLatin1.equals(value, aString.value);
    }

很明显了,肯定返回 false:

  • if 判断 ,肯定不相等,在内存中是两块不同的内存地址
  • return 三个 '并' 操作,只要其中任一个返回 flase,那么就返回 flase
    • anObject instanceof String aString 很显然这一句,不满足。Long 类型不继承于 String ,所以肯定返回 false。

解决

既然 String#equals 不行,那么换个位置,Long 类型在前面可以不?
直接看 Long#equals 源码

   public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }

当然不行,Long#equals 会先判断是否是 Long 类型的。


既然不论是 String 还是 Long 都会先判断类型,那么我们只需要将 String 转成 Long,或者将 Long 转成 String 比较即可。

总结

很多代码一眼看上去是那样的,但是不是的,嘿嘿嘿。不明白就先反编译,这样多数都能给到你提示,能明白为啥。再不懂就一行行 debug 看源码。

细节之下无魔法