[置顶] ==和equals怎么用?java如何判断相等

时间:2023-02-09 16:18:41

相信很多人都已经习惯了用==符号判断值是否相等。大部分人也都知道对于对象来说==号其实也就是比较两个对象的内存地址。但是为什么有的时候使用==就可以判断相等,而有的时候,必须要使用equals呢?

1.基本数据类型,如int,long,float,char,byte等:使用==判断是否相等是没有问题的。对于值类型,jvm将其存储在栈中,==即直接比较栈中两者内容。

2.一般引用类型,对于引用类型==就是比较引用所指向的地址,对象的引用也是存储在栈中的,==其实就是比较引用的内容,联想C的指针。如果你想判断两个引用是否指向的是同一个对象,那么==也没有什么都不对。但是如果你希望判断对象内部的值是否相等,那么==毫无疑问是不适合的。这是好你就需要重写该对象类型的equals方法,使用equals判断。

3.基本数据类型的包装类型,如Integer,Long,Float,等,包括String,java有个特性自动装箱拆箱。拿int和Integer来说,这两个其实不是一个东西,但是他们互相比较运算貌似也没什么违和感,对于java,3这个数就是值类型,之所以可以直接写成Integer i = 3;是因为编译器给你自动装箱了,实际编译器会理解为Integer i=Integer.valueOf(3);String其实也是如此,是引用类型,==比较的是地址,所以直接使用==是不安全的。

    3.1).Integer对比Integer:对于Integer,jvm在自动装箱的时候会自动缓存-128~127的值所对应的对象(可以设置),也就是说,在-128~127之间比较使用==是没有问题的。Integer a = 3;Integer b = 3;a和b指向的是同一个缓存对象。Integer类的缓存源码如下。一旦值不在范围内,就必须使用equals,Integer类默认实现了equals。

   private static class IntegerCache {//内部类,注意它的属性都是定义为static final
static final inthigh; //缓存上界
static final Integer cache[];//cache缓存是一个存放Integer类型的数组

static {//静态语句块
final int low = -128;//缓存下界,值不可变

// high value may beconfigured by property
int h = 127;// h值,可以通过设置jdk的AutoBoxCacheMax参数调整(参见(3))
if (integerCacheHighPropValue !=null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
// 通过解码integerCacheHighPropValue,而得到一个候选的上界值
int i = Long.decode(integerCacheHighPropValue).intValue();
// 取较大的作为上界,但又不能大于Integer的边界MAX_VALUE
i = Math.max(i, 127);//上界最小为127
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h; //上界确定,此时high默认一般是127
// 创建缓存块,注意缓存数组大小
cache =new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k <cache.length; k++)
cache[k] =new Integer(j++);// -128到high值逐一分配到缓存数组
}

private IntegerCache() {}//构造方法,不需要构造什么
}
3.2).Integer与int(包括直接写值)比,例如int a = 200;Integer b = 200;,比较a==b或b==200;不论是非在缓存范围内,比较都是成立的。因为包装类和值类型==比较,编译器会自动拆箱将Integer拆成值类型,其实最后是两个值类型比较。

     3.3).Integer需要注意的其他地方,例如Integer a = new Integer(3);Integer b = 3;a==b其实等于false,为什么呢?这里使用了new关键字,就是新建了一个新的Integer对象,不经过缓存,所以a和b是两个不同的对象。如果是Integer a = Integer.valueOf(3);Integer b = 3;a==b答案是true,很简单,看valueof源码就明白了:

 public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
      3.4)String类型,类似Integer,String也有缓存,不过是没有范围的,只要两个字符串内容相等,通过自动装箱得到的String类型都会指向同一个缓存,注意一定是自动装箱的String类型,即String a = “hello”;如果你是new出来的String对象,和上面Integer一样,也是两个对象。例如String s1 = "hello";String s2 = new String("hello");s1==s2;false。同样"hello"==s2也为false,因为s2不在缓存中,s1和“hello”(自动装箱)虽然在缓存中但是s2不在所以不是同一个对象。

    3.5)String与+。拼接String 我们习惯使用"hello"+"world"。要注意的是String s1 = “he”;String s2 = s1+“llo”;这时候s2引用已经不在指向s1的对象。s1+“llo”生成了一个新的“hello”对象在缓存中,s2便指向这个对象。综上无论String还是Integer个人认为使用equals比较安全。

4.最后,其他的包装类型和String和Integer类似,要注意装箱拆箱,以及缓存机制。