• equals()方法详解


      Java语言中equals()方法的使用可以说比较的频繁,但是如果轻视equals()方法,一些意想不到的错误就会产生。哈哈,说的有点严重了~

      先谈谈equals()方法的出身。equals()方法在java.lang.Object类中声明,由于Object类是Java所有类的基类,因此equals()方法在Java中无所不在,我也是惊呆了。先贴一

    段java.lang.Object类的英文说明:  

      Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.

      翻译一下:Object类是类继承树中的根类。每个类都把Object类作为其超类。所有的对象,包括数组,都实现了Object类所有的方法。

      

      java.lang.Object类中的equals()方法如何声明的呢?源代码是这么写的:

    1 public boolean equals(Object obj) {
    2     return (this == obj);
    3 }

      稍微解释一下,这段代码就是说如果有 obj1.equals(obj2),那么返回值就是判断obj1和obj2堆地址是否相同(也就是说是否是同一块内存,即是否是同一个对象)。

      阶段性总结一下java.lang.Object类的equals()方法:

      1) equals()方法使用必须要有2个对象;

      2) equals()方法返回的是一个boolean值,如果是同一个对象则返回true,否则返回false;

      3) equals()方法本质还是使用了"=="双目运算符。("==":基本数据类型比较内容是否相同;引用数据类型比较对象hashCode是否相同,即引用指向的对象是否是同一个)。

        摘自java.lang.Object类的equals()方法说明:equal objects must have equal hash codes

      

      解释完Object类的equals()方法后,我试着用例题的形式来分析一下这些继承Object类的派生类equals()方法。一般来说Java核心类库中的类几乎都有equals()的重写,但是

    自己写的类就没有重写咯。如果你没区别这两者就贸然使用equals()方法,那很可能还是在使用Object类的equals()方法。

    类型一: Object类的派生类没有重写Object类的equals()方法

     1 class MyClass{
     2     int x;
     3 
     4     MyClass(int i){
     5         x=i;
     6     }
     7 
     8     public static void main(String[] args){
     9         MyClass m1=new MyClass(100);
    10         MyClass m2=new MyClass(100);
    11         if(m1.equals(m2)){
    12             System.out.println("Both are equal");}
    13         else{
    14             System.out.println("Both are not equal");
    15         }
    16     }
    17 }

       A代码编译时报出错误提示信息"equals()方法未定义"

       B.编译通过,抛出运行期异常.

       C.输出Both are equal.

       D.输出Both are not equal

      分析:做错这道题的原因很多,但是做对这题的原因只有一个,那就是真正理解了equals()方法的前因后果。本题中MyClass类隐继承了Object类(所有类的基类),但是并没

    有重写Object类中的equals()方法。因此情况就是MyClass类和Object类的equals()方法是同一个,只不过MyClass类调用Object类的equals()方法而已。

     1 public class MethodOverrideVsOverload {
     2     public boolean equals( MethodOverrideVsOverload other ) {
     3         System.out.println("MethodOverrideVsOverload equals method reached" );
     4         return true;
     5     }
     6  
     7     public static void main(String[] args) {
     8         Object o1 = new MethodOverrideVsOverload();
     9         Object o2 = new MethodOverrideVsOverload();
    10  
    11         MethodOverrideVsOverload o3 = new MethodOverrideVsOverload();
    12         MethodOverrideVsOverload o4 = new MethodOverrideVsOverload();
    13   
    14         if(o1.equals(o2)){
    15             System.out.println("objects o1 and o2 are equal");
    16         }
    17  
    18         if(o3.equals(o4)){
    19             System.out.println("objects o3 and o4 are equal");
    20         }
    21     }
    22 }
    23 输出结果为:
      MethodOverrideVsOverload equals method reached
      objects o3 and o4 are equal

       分析:这道题不仅考察了"重写",也考察了"向上造型"现象。如果这道题做错,我感觉很可能是你认为下面这段代码是重写了java.lang.Object类的equals()方法。

    1 public boolean equals( MethodOverrideVsOverload other ) {
    2     System.out.println("MethodOverrideVsOverload equals method reached" );
    3     return true;
    4 }

      其实不然,java.lang.Object类equals()方法的签名和这个方法的签名是不一样的,不一样在哪?一看就知道是参数列表嘛,两个字母差这么多呢~。所以啊,Object o1,o2

    指向子类对象的情况并不是方法重写,只是发生了方法重载,o1和o2仍然会调用java.lang.Object类的equals()方法。不明白的建议温故一下方法重载(overload)&重写

    (override)这两者。关于Java"向上造型"语法现象具体机制我会专门写一篇总结来解释的。

    类型二:Object类的派生类重写了Object类的equals()方法 

      其实在Java Core Class Library中几乎都重写了java.lang.Object类的equals()方法。下面仅仅举2个常见的重写equals()方法的类。

      (1) String类重写Object类的equals()方法 

     1 public boolean equals(Object anObject) {
     2     if (this == anObject) {
     3         return true;
     4     }     
     5     if (anObject instanceof String) {
     6         String anotherString = (String)anObject;
     7         int n = count;
     8         if (n == anotherString.count) {
     9             char v1[] = value;
    10         char v2[] = anotherString.value;
    11         int i = offset;
    12         int j = anotherString.offset;
    13         while (n-- != 0) {
    14             if (v1[i++] != v2[j++])
    15               return false;
    16         }
    17         return true;
    18         }
    19     }
    20     return false;
    21 }                    

       下面分析一下String类equals()方法的源代码: 

    1 if (this == anObject) {
    2     return true;
    3 }   // 这段其实就是Object类的翻版,功能一模一样

      主要用于String类在constant pools(方法区常量池)的判断,如果是同一个对象那么就不用再判断两个对象是否内容相同了。写在开头是必须的,你说勒!

     1 if (anObject instanceof String) {
     2     String anotherString = (String)anObject;
     3     int n = count;
     4     if (n == anotherString.count) {
     5         char v1[] = value;
     6       char v2[] = anotherString.value;
     7       int i = offset;
     8       int j = anotherString.offset;
     9       while (n-- != 0) {
    10           if (v1[i++] != v2[j++])
    11              return false;   // 一有内容不同就返回false
    12        } 
    13        return true;  // 字符串内容均相同则返回true
    14     }
    15 }
        

      如果传入的是String类的对象,那么就是两个对象的内容比较,如果一有内容不同就返回false,均相同则返回true。

      (2) Arrays类重写Object类的equals()方法

      Arrays类的equals()方法有些区别,就是只加了static修饰符,当然这仍然是方法重写(只要派生类访问权限大于等于超类派生类返回值类型是超类的子类,并且方法签名相

    ,那么就可以方法重写)。而且Array类的equals()方法还重载了蛮多的,下面就举其中的long型(第一个)的例子加以说明:

    public static boolean equals(long[] a, long[] a2) {
        if (a==a2)
            return true;   // 如果数组引用指向同一个数组对象,那么显然是相同,返回true
        if (a==null || a2==null)
            return false;  // 两个比较的数组不能是null
    
        int length = a.length;
        if (a2.length != length)
            return false;  // 如果两个数组不等长,显然也不可能相等
    
        for (int i=0; i<length; i++)
            if (a[i] != a2[i])
                return false;  // 如果两个数组等长,那么比较数组的元素,如果所有元素相同,那么这两个数组相同,反之不同
        return true;
    }

    总结:

    1) 对于equals()方法,无论如何都不能太轻视。在equals()内部其实也是有"=="在实现部分功能的。

    2) 对于基本数据类型,"=="比较的变量的内容是否相同;对于引用数据类型,"=="比较的是对象的地址是否相同。

    3) String类的equals()方法比较的是字符串是否内容相同。很多人误用,我猜可能就是这家伙惹的祸吧,嘻嘻~。

  • 相关阅读:
    js连等赋值与对象引用
    es6读书笔记(四)——顶层对象
    es6读书笔记(三)——const
    es6读书笔记(二)——块级作用域
    es6读书笔记(一)——let
    Idea工具使用junit运行单元测试(三):测试套件
    Python学习笔记(十二):列表生成式、三元表达式、字典排序
    python学习笔记(六):内置函数
    扫描歌曲
    为Activity设置特定权限才能启动
  • 原文地址:https://www.cnblogs.com/forget406/p/5047020.html
Copyright © 2020-2023  润新知