题目背景:输出 true OR false 「基于 JDK8」
long id=45;
System.out.println("45".equals(id));
给答案
输出 false
猜想
一眼看到题目:肯定输出 true 啊,这还用想?结果自然打脸
- long 类型的缓存问题?
- long 类型的自动转换问题?
验证:
- 我使用的是 equals :在 Java 中是比较值的;== :在 Java 才是比较内存地址的(可能会有问题)。所以使用 equals 是不会出问题的。
- 自动转换问题:反编译 .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 看源码。
细节之下无魔法