Java 中equals和==的区别
一. 对于基本类型的变量。"=="和"equal"的区别
(1)“==”对于基本数据类型,是判断两个变量的值是否相等。只要他们的值相同,==的比较就返回true。
“equal”不能用于基本数据类型。只能用于类变量。对于基本数据类型要用其包装类。比如Boolean.Character.Byte.Shot.Integer.Longer.Float.Double等包装类,在这里==比较的是地址,看二者是否引用同一个堆内存空间,如果是,则返回true。而“equal”是比较内容的。
二.对于对象变量,"=="和"equal"的区别
“==”比较的是值,这个值也就是内存中存放的对象的(堆)内存地址。所以,如果即使对象的值相等,但是他们的内存地址不同,==比较的结果还是为false。故“==”用于比较两个变量的值是否相等,就是判断它们是否是同一份内存数据。而不是判断变量引用的对象是否相等
“equal”用于比较两个对象是否相等,也就是双方对象中的内容是否相等,不是比较内存地址。
所以所有需要进行对像是否相同的比较,都要用到equals方法。而equals的使用,只依赖于所使用的那个类是如何实现(重写)该方法的。当然根据需要,我们可以自行实现是比较对象内的内容值是否相同,或者直接比较对象的内存地址,当然还可以是结合二者的比较形式,例如,我们最常见的String类型中的“equals”方法,
public boolean equals(Object anObject) {
if (this == anObject) {//它是首先直接比较对象的内存地址
return true;
}
if (anObject instanceof String) {//若不等,则再进行比较内容值,再返回结果。
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
我们都知道java中所有的类都默认继承于Object,所以若某类没有重载它的“equals”方法,则默认使用Object的equals方法,而Object的equals方法,是直接比较对象的内存地址。
public boolean equals(Object obj) {
return (this == obj);
}
所以对于“equals”的比较方式,是取决于类是否重载了Object类中的方法,若未重载,则与==的比较方式相同。
三 、几个重载的equals方法的使用
1.对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,这个前面已经说过了,其比较方法是不同的。
“==”比较两个变量本身的值,即两个对象在内存中的首地址。
“equals()”比较字符串中所包含的内容是否相同。
听老师讲解说,在虚拟机中,是存在字符串池的。它里面保存着String对象。
//字符串类型的比较
String str1="abc";
String str2="abc";
String str3=new String("abc");
System.out.println("str1==str2??"+(str1==str2));
//返回的结果是: str1==str2??true
System.out.println("str1.equals(str2)的结果??"+str1.equals(str2)); //返回的结果是: str1.equals(str2)的结果??true
System.out.println("str1==str3??"+(str1==str3));
//返回的结果是: str1==str3??false
System.out.println("str1.equals(str3)的结果??"+str1.equals(str3));
//返回的结果是: str1.equals(str3)的结果??true
str1和str2时,这两个对象就是加入到字符串池中的。而且当创建好了第一个str1时,就将“abc”存放在里面,当创建第二个str2时,虚拟机就会首先去它的字符串池中搜索,看能否找到对应的,也就是相同的字符串,如果存在,就直接将已经存在的那个对象的引用给要创建的对象的引用。若不存在,则创建一个新的对象,并返回一个新对象的引用给要创建的对象的引用。
true,但是为什么第三条输出语句返回的是false呢?这是因为当创建str3时,我们用的是new,而这种方法创建的字符串是不放在那个池里面的。故得到的结果会是false了。而且我们应该知道,只要是使用了new的,就是一个新的对象了。
2.对于队列list中的比较。
“==”比较两个变量本身的值,即两个对象在内存中的首地址。
在这里我们还需要注意的是list存储的对象的类型,如果两个list容器存放的是不同的类型对象,则不能进行比较。这其实就相当于比较不同类型的对象,这是不允许的,程序编译时会报强制类型转换的错误。当然也可以用来比较同一个容器中的不同对象是否指向同一个内存地址。
“equals()”比较会先比较他们的内存地址是否相同,若不是,则看括号中的对象是否是list的实例,若不是则直接返回false,若是,遍历他们中的对象来进行比较。下面是list中重写的equals方法。
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while(e1.hasNext() && e2.hasNext()) {//比较两个容器中的同一位置上的元素是否相同,若不同,则返回false.若两个容器中的个数不一样时,则返回false
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
//队列中的比较
ArrayList<String> list=new ArrayList<String>(); //创建一个用于存储String 类型的list容器
list.add(str1); //将创建的三个字符串对象添加到lisst中
list.add(str2);
list.add(str3);
ArrayList<Character> list1=new ArrayList<Character>(); //创建一个用于存储Character类型的list1容器
ArrayList<String> list0=list; //将list和liet0指向同一个内存地址
ArrayList<String> list11=new ArrayList<String>();
list0.add(str1);list0.add("dt");
list0.add(str2);
list0.add(str3);
boolean b0=list.get(0)==list.get(1); //打印的结果是 : true .这里是因为实际上是用”==“比较str1和str2
boolean ab=list.get(0)==list.get(2); //打印的结果是 : false 这里是因为实际上是用“==”比较str1和str3
boolean b1=list.equals(str3); //打印的结果是 : false 这里因为是list来调用equals方法,而这个方法是重写了的。
boolean b3=list==list0; //打印的结果是 : true
boolean b11=list==list11; //false
boolean b2=list1.equals(list); //打印的结果是 : false
boolean bb=list.equals(list0); //打印的结果是 : true
for(int i=0;i<list.size();i++){
System.out.println("我是第"+i+"个元素"+list.get(i));
}
System.out.println(b11+"%%%%"+b0+" "+ab+"#### "+"-->>>"+b1+"<<<>>>>"+b2+">>>>"+bb+"@@@"+b3);
我是第0个元素abc
我是第1个元素abc
我是第2个元素abc
我是第3个元素abc
我是第4个元素dt
我是第5个元素abc
我是第6个元素abc
false%%%%true false#### -->>>false<<<>>>>false>>>>true@@@true
3.“set”中的比较
因为set本身就是无序的,我们必须通过迭代器才能取得它里面的元素,所以,在set中就不存在e.equals(e1)满足的情况,如果使用“==”比较两个set容器对象,我们都知道它的结果肯定是false。因为,它们都是新创建的对象,内存地址不一样,所以使用“==”的结果的结果是false就不奇怪了。
“equals“的比较方法也是重载的,方法的代码如下:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
try {
return containsAll(c);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
我们可以知道,它们是先比较内存地址的,若相同则肯定是同一份数据,直接返回true了。若不是,则需要判断括号中的是不是set的实例,若不是则肯定不需要在比较了,直接返回false就行了。因为它们都不是同一种类型的比较了。若是两个set的实例做比较,则首先看它们大小是否相同,若大小不同了,我们也就知道答案了。在大小相同的情况下,再比较它们的内容,所以这里可以使用set里面的containsAll()方法来比较更快些。
HashSet<String> set=new HashSet<String>();
set.add(str1);set.add(str2);set.add(str3);set.add("ft");set.add("eded");
System.out.println(set.size());//没添加最后的那个元素时,大小是2
HashSet<String> set1=new HashSet<String>();
set1.add(str3);set1.add(str2); //set1.add(str1);
set1.add("ft");
System.out.println(set1.size());
boolean boo=set==set1; //返回的结果总是false
boolean bl=set.equals(str1); //返回的结果也还是false,因为这是不同类型的比较
boolean bo1=set.equals(set1); //set没有添加最后的那个元素时,它们比较的结果是true,若加上了最后那个,则它们的大小就已经不相同了,故在此比较的结果是false了。
boolean bo2=set1.equals(set);
System.out.println(bo1+"--"+bl+" "+bo2+"@@@2"+boo); }