💥为什么要写这么一篇文章
今天同事遇到一个问题,测试那边进行反馈说两个用户出现不同的问题。后面经过排查发下。在比较用户ID是否与数据库中的一条数据的ID是否一致时遇到的问题。当用户ID是1L(Long类型非long),判断结果为true,而当另外一个用户ID是2912L时,判断结果却为false。为什么会出现这种问题呢?我当时只是觉得Long毕竟是个对象应该通过equals进行比较。后面为了深入了解,才发现不仅仅是那样。
问题如下
第一段代码
Long a=50L;
Long b=50L;
System.out.println(a==b);//a==b的结果true
第二段代码
Long c=128L;
Long d=128L;
System.out.println(c==d);//c==d的结果false
🎨两个执行比较,却是不相同的结果。产生这类的原因,查看源代码得知:
/**
* Returns a {@code Long} instance representing the specified
* {@code long} value.
* If a new {@code Long} instance is not required, this method
* should generally be used in preference to the constructor
* {@link #Long(long)}, as this method is likely to yield
* significantly better space and
* time performance by caching
* frequently requested values.
*
* Note that unlike the {@linkplain Integer#valueOf(int)
* corresponding method} in the {@code Integer} class, this method
* is <em>not</em> required to cache values within a particular
* range.
*
* @param l a long value.
* @return a {@code Long} instance representing {@code l}.
* @since 1.5
*/
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);
}
🎨个人通过翻译工具稍微翻译了一下方法注释,如有不对之处,可以帮忙指出一下。
返回一个{@code Long}实例,表示指定的{@code Long}值。
如果不需要新的{@code Long}实例,则通常应该优先使用此方法而不是构造函数{@link #Long(Long)},因为该方法通过缓存频繁请求的值可能会产生更好的空间和时间性能。
注意,与{@code Integer}类中的{@linkplain Integer#valueOf(int)对应方法}不同,该方法<em>不是</em>需要缓存特定范围内的值。
✒️非常粗糙的翻译,但是大致也能知道这个方法是通过缓存特定范围内的值,以达到更好的空间和时间性能。从方法体中也可以看到LongCache缓存以及当Long的值在[-128,127]之间是不会new一个实例的。而当Long的值不在在[-128,127]之间内时候则会进行new出一个实例,这样就导致==比较时出现错误
。
解决方案
方案一
Long c = 128L;
Long d = 128L;
c.longValue() == d.longValue() //true
方案二(推荐)
Long c = 128L;
Long d = 128L;
c.equals(d);//true
Long中的equals源码
/**
* Compares this object to the specified object. The result is
* {@code true} if and only if the argument is not
* {@code null} and is a {@code Long} object that
* contains the same {@code long} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}