【问题标题】:Why should the parameter of an equals() method of a new class be of type Object?为什么新类的equals()方法的参数应该是Object类型?
【发布时间】:2017-03-18 22:59:32
【问题描述】:

我正在重读 Stuart Reges 的 Building Java Programs 并注意到一些我不太理解的东西。它与在任何新类中重载 equals() 方法有关。假设我们这样定义一个类:

public Point{  
   private int x;
   private int y;

   public Point(int x, int y){
       this.x = x;
       this.y = y;
   }

   public getX(){
       return this.x;
   }

   public getY(){
       return this.y;
   }
}

这本书建议,任何时候我们定义一个新类,我们为一个新类定义的 equals() 方法都应该这样写:

public boolean equals(Object o) {
     if (o instanceof Point) {
          Point other = (Point) o;
          return x == other.x && y == other.y;
      } else { 
          return false;
      }
}

为什么 equals 方法应该接受泛型类型“Object”而不是“Point”类型的对象?这本书说,如果 equals 方法头与泛型 Object 类的 equals 方法头不匹配,它将不会被重载(我知道它不会被重载,否则)。然而,这有点不直观,因为它们实际上可能相等的唯一时间是它们是否属于同一类型......

当我将一个 String 对象作为参数传递给我的 equals() 方法时,该方法接受 Point 类型的参数,而不是 String,它正确返回 false。每当我们传递不同的类型时,通用的 equals() 方法(比较内存地址)不适合吗?

【问题讨论】:

  • 考虑这样一种情况,您可能有一个存储文本表示的类,类似于字符串(但具有一些附加功能)。是否存在您希望 equals() 和 hashCode() 语义导致它与具有相同内容的 String 对象进行比较的情况?

标签: java inheritance overloading


【解决方案1】:

不一定正确。在某些用例中,equals 可以表示具有相等值的两个对象,即使它们来自两个不同的类。

例如,考虑ArrayList(或AbstractList 的任何其他子类)。根据其语义,如果两个Lists 具有相同顺序的相同元素,则它们被认为是相等的。因此,ArrayList 可能等于任何类型的List,无论是LinkedList、另一个ArrayList,甚至是我自己实现的List

【讨论】:

    【解决方案2】:

    考虑这样一个案例:

    public class BoatWeight {
        float weightTonnes;
        public float getWeightTonnes() {
            return weightTonnes;
        }
    }
    
    public class CarWeight {
        int weightLb;
        public int getWeightLb() {
            return weightLb;
        }
    }
    

    它们是可比的。但前提是你定义了逻辑:

    public class CarWeight {
        ...
        public boolean equals(Object o) {
             if (o instanceof BoatWeight) {
                 final int boatWeightLb =
                     WeightConverter.tonnesToLb(o.getWeightTonnes());
                 return  boatWeightLb == this.getWeightLb();
             } else if (o instanceof CarWeight) {
                 return this.getWeightLb() == o.getWeightLb();
             }
        }
        ...
    }
    

    显然可以通过使用通用接口和相同的度量单位来清理上述内容,然后将其用作equals()的类型。但是,如果您使用库中的类怎么办?你不能那样做。对象是所有...对象中唯一通用的接口。

    【讨论】:

      【解决方案3】:

      这是因为你覆盖了

      boolean equals(Object o){}
      

      在 Object 类中定义。它必须对任何对象都足够通用,因为它在“继承根”中定义。

      【讨论】:

      • 我明白了……我不明白为什么这是必要的。在我们在两种不同类型上调用 equals 的情况下,我从来没有看到不同类型的两个对象是如何相等的,因此泛型方法将始终有效
      • 该语言允许您比这更通用。如果你想比较动物和猫怎么办?您可能想要这样做
      【解决方案4】:

      为什么不两者兼得——保存instanceof检查,在哪里可以静态确定正确的重载,但仍然正确重载基方法,因此在将点存储在集合等时它可以工作:

      @Override
      public boolean equals(Object o) {
        return (o instanceof Point) ? equals((Point) o) : false;
      }
      
      public boolean equals(Point other) {
        return x == other.x && y == other.y;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-06
        • 2013-11-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多