Java:要在一个充满自定义对象的ArrayList中使用包含,我应该覆盖等于或实现可比/比较器吗?

我有一个充满这些的数组列表:

class TransitionState {

    Position positionA;
    Position positionB;

    int counter;

    public boolean equals (Object o){

        if (o instanceof TransitionState){

          TransitionState transitionState= (TransitionState)o;

          if ((this.positionA.equals(transitionState.positionA))
                  &&(this.positionB.equals(transitionState.positionB)))
          {
              return true;
          }
        }
     return false;

    }

    @Override
    public String toString() {

        String output = "Position A " + positionA.i+ " "+ positionA.j + " "+ positionA.orientation + " "+
                "Position B " + positionB.i + " "+ positionB.j + " "+ positionB.orientation;

        return output;
    }

}

class Position {

    int i;
    int j;
    char orientation;

    Position() {

    }


    void setIJ(int i, int j){
        this.i=i;
        this.j=j;
    }

    void setOrientation(char c){

        orientation = c;
    }

   public boolean equals(Object o){

        if(o instanceof Position){

          Position p = (Position)o;
          if((p.i==this.i)&&(p.j==this.j)&&(p.orientation==this.orientation))
          {
              return true;
          }
              else return false;

        }

            return false;
   }

} //end class Position

我用这个查询它:

 if(!transitionStatesArray.contains(newTransitionState)){  //if the transition state is new add and enqueue new robot positions

                 transitionStatesArray.add(newTransitionState); //marks as visited

我在 里面发现了重复的元素,为什么会这样?transitionStatesArray

我使用这些i,j和方向值来填充矩阵中的唯一值,但在这里我有一个副本:

 S  .  N 
 *  *  * 
 .  D  D 


 E  .  O 
 *  *  * 
 .  D  D 


 N  .  S 
 *  *  * 
 .  D  D 


 S  .  N 
 *  *  * 
 .  D  D 

答案 1

定义该方法用于确定参数对象是否由列表“包含”。所以你需要覆盖...假设默认实现不是您需要的。List.contains(...)equals(Object)equals

但是,您需要注意,可能会针对列表中的每个元素测试参数。对于一长串来说,这很昂贵。根据应用程序的详细信息,最好使用不同的集合类型(例如 ,或 ),而不是 .如果您使用其中之一,您的类将需要重写或实现,或者您需要创建一个单独的...取决于你的选择。List.contains(...)HashSetTreeSetLinkedHashSetListhashCodeComparableComparator


(关于替代方案的更多建议...因为OP感兴趣)

在类似 或 的类型上的 性能是 。最坏情况下的调用成本与列表长度成正比。containsListArrayListLinkedListO(N)contains

对于 最坏情况,性能与 成正比。TreeSetcontainslog2(N)

对于 a 或 ,的平均性能是一个常数,与集合的大小无关,但最坏情况的性能是 。(最坏的情况是,如果您1)实现一个糟糕的函数,将所有内容散列为少量值,或者2)调整“负载因子”参数,以便哈希表不会随着它的增长而自动调整大小,则会发生最坏的性能。HashSetLinkedHashSetcontainsO(N)hashcode()

使用类的缺点是:Set

  • 它们是集合;即,您不能将两个或多个“相等”的对象放入集合中,并且
  • 它们不能被索引;例如,没有方法,以及get(pos)
  • 有些类甚至不保留广告订单。Set

在决定使用哪个集合类时,需要考虑这些问题。


答案 2

你可能需要实现 hashCode()。通常,无论如何,在覆盖等于时,您都应该始终执行此操作。

集合文档中

此规范不应被解释为暗示调用 Collection.contains with a non-null argument o 将导致为任何元素 e 调用 o.equals(e)。实现可以自由地实现优化,从而避免相等调用,例如,通过首先比较两个元素的哈希代码。(Object.hashCode() 规范保证两个哈希代码不相等的对象不能相等。更一般地说,各种集合框架接口的实现可以自由地利用基础 Object 方法的指定行为,只要实现者认为合适。


推荐