龙珠

修炼自己与发现世界

(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(); 则效果与前一种方法相同,会先检查字符串缓冲池中是否存在,若存在,则返回已存在的对象引用。


参考资料:

  1. java中equals和==的区别

  2. Java String类的equals源代码研究