(Java)相同和相等:equals() == "=="?
Java中,equal()方法和“==”之前并不了解有什么区别,上次python学习小组的时候,麦片有讲了这点,回来自己查了下源代码和资料,结果如下:
Object中,equal()源码如下:
---------------------
/**
* Indicates whether some other object is "equal to" this one.
* <p>
* The {@code equals} method implements an equivalence relation
* on non-null object references:
* <ul>
* <li>It is <i>reflexive</i>: for any non-null reference value
* {@code x}, {@code x.equals(x)} should return
* {@code true}.
* <li>It is <i>symmetric</i>: for any non-null reference values
* {@code x} and {@code y}, {@code x.equals(y)}
* should return {@code true} if and only if
* {@code y.equals(x)} returns {@code true}.
* <li>It is <i>transitive</i>: for any non-null reference values
* {@code x}, {@code y}, and {@code z}, if
* {@code x.equals(y)} returns {@code true} and
* {@code y.equals(z)} returns {@code true}, then
* {@code x.equals(z)} should return {@code true}.
* <li>It is <i>consistent</i>: for any non-null reference values
* {@code x} and {@code y}, multiple invocations of
* {@code x.equals(y)} consistently return {@code true}
* or consistently return {@code false}, provided no
* information used in {@code equals} comparisons on the
* objects is modified.
* <li>For any non-null reference value {@code x},
* {@code x.equals(null)} should return {@code false}.
* </ul>
* <p>
* The {@code equals} method for class {@code Object} implements
* the most discriminating possible equivalence relation on objects;
* that is, for any non-null reference values {@code x} and
* {@code y}, this method returns {@code true} if and only
* if {@code x} and {@code y} refer to the same object
* ({@code x == y} has the value {@code true}).
* <p>
* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
*
* @param obj the reference object with which to compare.
* @return {@code true} if this object is the same as the obj
* argument; {@code false} otherwise.
* @see #hashCode()
* @see java.util.HashMap
*/
public boolean equals(Object obj) {
return (this == obj);
-----------------------
可以看出,在Object中,equals()方法和“==”判断是等价的。
那么二者有什么区别呢?毕竟如果相同的话,就不必要存在两个相同的判断方法了。
我们一般而言,对两个对象的判断是否相同,有两种判断:
1.是否引用了同一个对象,即:一个对象,两个引用;
2.两个对象是否内容相同,即:两个对象,引用不同,但内容相同。
这样就明了了,对第一种的判断,其实是对二者的内存地址是否相同进行判断,内存地址相同,二者就是引用自同一个对象;对于第二种的判断,是对二者内容的判断,引用地址相不相同、是不是同一个对象没有关系,只要内容相同即可。
通常第一种判断为“==”方法;第二种判断为equals方法。
当然,“==”方法还可以判断基本数据类型是否相同,但是就对象而言,二者的区别就是看是不是指向同一个对象,若是,则“==”返回true;若二者内容相同(若二者指向同一个对象则必然内容相同),则equals()返回true。
对于equals()方法,如果自己设计类的时候,需要判断时一定要记得重写,否则自动调用object的equals方法就会按照“==”来进行判断了。
例如,String里面,对equals()方法进行重写后,就是对每个char进行判断是否一样,如下:
----------------
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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;
-------------------------
可以看出,String重写Object方法之后,先用“==”判断是否是同一引用,之后若长度相同,则对每个char判断是否相同,这样通过equals()方法来判断二者是否内容相同。
另外,这里面还有一些小的tricky。
正常情况下,两个String的判断如:
---------------
String s1 = new String("dad.ad.a");
String s2 = new String("dad.ad.a");
---------------
对二者的判断应该是“==”不同,equals()相同,这是没问题的。
但是,对于代码如下:
---------------
String s1 = "dad.ad.a";
String s2 = "dad.ad.a";
---------------
对这二者的判断,执行结果则全部为True!
为什么呢?
这是因为程序在运行的时候会创建一个字符串缓冲池,以String s2 = "dad.ad.a";这样的形式创建字符串的时候,程序会先在String缓冲池中寻找相同值的对象,从而s2中引用了s1所引用的对象。而在使用 new String("dadasda");这样的方法时,则是明确告诉程序需要新建一个String对象,因此不会从字符串缓冲池中提取。若对该方法使用new String("dadada").intern(); 则效果与前一种方法相同,会先检查字符串缓冲池中是否存在,若存在,则返回已存在的对象引用。
参考资料: