写在开始:
Long 封装类型比较,最好使用 compareTo 函数、equals函数或longValue函数获取基本类型long的值再比较。
问题描述:封装类Long类型的变量,相同的值,结果比较缺不相等。
直接上代码:
public static void main(String[] args) {
Long c = 128L; //等同于 Long c = Long.valueOf(128);
Long d = 128L;
System.out.println("c == d : " + (c == d)); //false
System.out.println("c.compareTo(d) : " + c.compareTo(d)); //0
}
//输出结果:
c == d : false
c.compareTo(d) : 0
换代码,注意c、d变量的值
public static void main(String[] args) {
Long c = 127L; //等同于 Long c = Long.valueOf(128);
Long d = 127L;
System.out.println("c == d : " + (c == d)); //true
System.out.println("c.compareTo(d) : " + c.compareTo(d)); //0
}
//输出结果:
c == d : true
c.compareTo(d) : 0
结论:
值范围在[-128,127]内的Long对象存放在常理池中。
两个Long封装类型的变量比较是否相等时,当值范围在[-128,127]间时,用 == 比较相同的值,是相等的。
超出这个范围使用 == 结果便不在正确。
应该使用compareTo:
public int compareTo(Long anotherLong) {
return compare(this.value, anotherLong.value);
}
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
【x.compareTo(y) 返回结果:-1:x < y, 0:x == y, 1:x > y】
或使用equals
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue(); //转成基础类型long进行值比较
}
return false;
}
另一种使用Long.longValue获取基本类型值再比较
分析:
Long c = 128L; (等同于 Long c = Long.valueOf(128);)
首先在栈中声明了一个基础类型long 128l, 然后调用Long.valueOf() 生成 Long类型的 128l,再赋值给c。
(tips:怎么知道会调用Long.valueOf()的?见文末)
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);
}
从上面代码可以看出,当long类型的值超出【-128,127】范围时,会执行 new 操作生成新的Long对象,这就导致c、d即使均赋值128l,但用==比较却不相等的原因,因为==对于引用类型只比较内存地址。
在【-128,127】范围内的值,会从常量池LongCache.cache 数组中获取对象,所以c、d赋值127l时,实际是从LongCache.cache数组中获取了同一个Long对象,所以==比较是相等的。
private static class LongCache {
private LongCache(){}
//定一个了一个长度为256的数组
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
//将【-128,127】的Long对象放到cache[]中
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
另一种情况,见代码
public static void main(String[] args) {
Long a = 1000L;
long b = 1000L;
System.out.println("a == b:" + (a == b)); //true
}
//输出结果:
a == b:true
a==b 比较时,a会先调用Long.longValue 获取基本类型long的值,然后在于b进行比较,所以 a==b 为true
最后:
Long c = 128L; 怎么知道调用Long.valueOf函数的?
查看class文件的字节码。命令:javap -c class文件名称(不用带.class)
最直观的方式,打断点。
//源码
package com.experiment;
public class LongTest {
public static void main(String[] args) {
Long a = 128L;
}
}
//class
package com.experiment;
public class LongTest {
public LongTest() {
}
public static void main(String[] args) {
Long a = 128L;
}
}
//字节码
public class com.experiment.LongTest {
//构造函数
public com.experiment.LongTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
//mian主函数
public static void main(java.lang.String[]);
Code:
0: ldc2_w #2 // long 128l //在栈中分配一块空间,类型为long 值为128l
3: invokestatic #4 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long; //调用静态方法 Long.valueOf
6: astore_1 //将栈顶引用类型值保存到局部变量1中。
7: return
}