【问题标题】:Generic deep compare equals通用深度比较等于
【发布时间】:2009-09-01 14:47:12
【问题描述】:

基本上我不想比较元素,而是你包含的元素。如果跟随会起作用,那就太酷了,但它不起作用。

public boolean equals(Ie<T> that) {
    T This = this.value;
    T That = that.value;
    boolean x = That.compareTo(This) == 0;
    return x;
}

我所做的是:

public boolean equals(Object obj) {
    if (obj == null)
        return false;

    String tmp = obj.toString();
    if (this.value instanceof Integer)
        return equalsInt(new Ie<Integer>(Integer.parseInt(tmp)));
    // etc.

    return false;
}

public boolean equalsInt(Ie<Integer> ie) {
    Integer This = this.value.intValue();
    Integer That = ie.value;
    boolean x = That.compareTo(This) == 0;
    return x;
}

这是一个明显的蛮力解决方案。没有obj.toString();+新元素可以吗?

编辑:

Ie类定义为:

public static class Ie<T extends Number & Comparable<? super T>>
        extends Number implements Comparable<Ie<T>> {

类与方法相比相当简单:

public int compareTo(Ie<T> that) {
    T This = this.value;
    T That = that.value;
    return (This.compareTo(That) < 0 ? -1 : (This
            .compareTo(That) > 0 ? 1 : 0));
}

我正在使用 Collection addall 方法中的类,其中 contains 正在调用 equals。

Erikson 解决方案运行良好:

@Override
public boolean equals(Object that) {
    if (that == null)
        return false;
    if (this == that)
        return true;
    if (that instanceof Ie<?>) {
        Object ThisValue = this.value;
        Object ThatValue = ((Ie<?>) that).value;
        return ThisValue.equals(ThatValue);
    }

    return false;
}

【问题讨论】:

  • 我并没有真正理解你的问题和你的目标。您只想比较两个对象吗?如果是这样,您应该比较对象的每个属性。请澄清您的问题。

标签: java generics


【解决方案1】:

为此,每个类型T 都必须实现Comparable 接口,并且每个实现Comparable 的类都应该以一致的方式实现equals。所以,Matt Ball's 回答就足够了。

但是,如果由于某种原因没有,则需要一个解决 Java 类型擦除的解决方案。通过显式指定T 的类型,可以进行必要的类型检查。 Ie 类的部分定义如下:

class Ie<T extends Comparable<T>>
{

  private final Class<? extends T> type;

  private final T value;

  public Ie(Class<? extends T> type, T value)
  {
    this.type = type;
    this.value = value;
  }

  @Override
  public boolean equals(Object obj)
  {
    if (obj == this)
      return true;
    if (obj instanceof Ie) {
      Object that = ((Ie<?>) obj).value;
      if (type.isInstance(that)) {
        return value.compareTo(type.cast(that)) == 0;
      }
    }
    return false;
  }

}

【讨论】:

    【解决方案2】:
    @Override
    public boolean equals(Object that)
    {
        if (this == that)
          return true;
        if (that instanceof Ie) {
          Object ThisValue = this.value;
          Object ThatValue = ((Ie<?>) that).value;
          return ThisValue.equals(ThatValue);
        } else 
          return false;
    }
    

    【讨论】:

    • 这是一个令人困惑的 equals 方法,因为它没有正确覆盖 Object.equals(Object other)。 equals()的参数应该是Object,然后在运行时检查它是否等于这个对象。
    • 我很喜欢这里的基本思想,所以我把它修好了才能正常工作。希望你不要介意。
    • @erickson:ewwwww,instanceOf。但是,是的,感谢您的实施。
    • 好吧,如果你使用equals(Ie&lt;T&gt;) 方法,它不会覆盖Object.equals,所以你只需要使用instanceof
    • 嗯,还有其他方法可以确保“那个”是“正确”类型......取决于“正确”类型的含义。例如,您可能通过检查 getClass().equals(that.getClass()) 来要求 thisthat 是相同的运行时类型。但是,由于value 似乎在这里很重要,我认为instanceof 是合适的。
    【解决方案3】:

    首先,不要将equals() 与compareTo() 混淆。第一个显示两个对象是否相等。另一方面,比较试图找出哪个更大(在排序时很有用)。

    比较引入了相对论的元素。例如,如果您有一个 Person 对象列表,那么如果您按名称比较它们,那么人“Allun”比“Dave”小,但如果按年龄比较它们可能相等。即使他们在年龄方面相等,但根据 equals() 方法,它们并不相等,因为它们代表不同的人。

    关于 equals() 方法本身,这可能会对您有所帮助:

    class MyClass {
    
      int anInt;
    
      public boolean equals(Object obj) {
        if (obj instance of MyClass) {
          MyClass that = (MyClass) obj;
          return this.anInt==that.anInt;
        }
        return false;
      }
    }
    

    或者如果你有另一个对象并且你想检查 null:

    class MyClass {
    
      Object anObject;
    
      public boolean equals(Object obj) {
        if (obj instance of MyClass) {
          MyClass that = (MyClass) obj;
          return this.anObject==null ? that.object==null : this.object.equals(that.object);
        }
        return false;
      }
    }
    

    【讨论】:

      【解决方案4】:

      是的,最简单的方法是使用 Object.equals 方法来比较包含的对象(如 Matt Ball 的回答)。 但是,如果由于某种原因您不能使用它,您将不得不存储类型并进行一些动态类型转换(如在 erickson 的回答中),或者进行未经检查的转换,如下例所示:

      class Ie<T extends Comparable<T>>
      {
          public Ie(T value) {this.value = value;}
      
          private final T value;
      
          public boolean equals(Object obj) {
              if(obj == this)
                  return true;
      
              if(obj instanceof Ie<?>)
              {
                  Ie<?> That = (Ie<?>)obj;
      
                  if(value.getClass() != That.value.getClass())
                      return false;
      
                  // Cast to anything that allows calling typed equals(). 
                  // The type will be erased at runtime anyway.
                  return ((Ie<String>)this).equals((Ie<String>)That); 
              }
              return false;
          }
      
          public boolean equals(Ie<T> that)
          {
              return that.value.compareTo(this.value) == 0;
          }
      }
      

      【讨论】:

        【解决方案5】:

        如果您尝试比较泛型参数类型的实例,请考虑Ie&lt;String&gt;Ie&lt;Integer&gt;,这将引发ClassCastException

        我将为埃里克森提出一个稍微不同的解决方案。如果我们将Comparator 添加到Ie,我们可以委托比较。

        不利的一面是,这确实需要您创建一个Comparator(可能已定义equals),并且您不能在不安全的情况下获取Comparator 实例(例如Collections.emptyList)。

        class Ie<T> {
        
            private final Comparator<? super T> comparator;
        
            private final T value;
        
            public Ie(Comparator<? super T> comparator, T value) {
                if (comparator == null || value == null) {
                    throw new NullPointerException();
                }
                this.comparator = comparator;
                this.value = value;
            }
        
            @SuppressWarnings("unchecked")
            @Override
            public boolean equals(Object obj) {
                if (!(obj instanceof Ie)) {
                    return false;
                }
                Object other = (Ie<?>)obj;
                return
                     this.comparator.equals(other.comparator) &&
                     this.comparator.compare(this.value, (T)other.value) == 0
            }
        
            @Override
            public int hashCode() {
                return comparator.hashCode()*31 + value.hashCode();
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2012-03-26
          • 2021-10-10
          • 2016-11-18
          • 1970-01-01
          • 2012-02-13
          • 2014-07-18
          • 2018-02-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多