【问题标题】:Stack in Java, problem with "contains"Java中的堆栈,“包含”的问题
【发布时间】:2011-08-09 01:58:45
【问题描述】:

我在我的程序中使用堆栈,但是当程序尝试检查堆栈中包含的元素时出现问题。我在堆栈中使用整数数组。简短的例子是:

        Stack<int[]> myStack = new Stack<int[]>();
        myStack.push(new int[]{1,2});
        myStack.push(new int[]{1,3});
        myStack.push(new int[]{1,4});
        if (myStack.contains(new int[]{1,3})) {
            System.out.println("YES");
        } else {
            System.out.println("NO");
        }

现在它被打印为“NO”。我该怎么做才能得到“是”? 我知道问题在于我没有使用相同的对象,但实际上我的程序要大得多,我不能使用它

int[] myInteger = new int[]{1,3};
myStack.push(myInteger);
myStack.contains(myInteger);

【问题讨论】:

  • Stack 类(就像VectorHashTable)只是很久以前的宿醉,恕我直言不应该再使用了。不幸的是,Collections 框架的现代部分没有堆栈,但您可以通过继承 ArrayList 并实现两个简单的方法来创建一个。

标签: java stack contains


【解决方案1】:

这很简单:int[] 按身份进行比较,

new int[]{1,3}.equals(new int[]{1,3})

返回假。有很多解决方案:

  • 请改用List&lt;Integer&gt;。这效率很低,但可能就足够了。
  • int[]包装到一个对象中并实现equalshashCode
  • 使用像 trove4j 这样的原始集合库,它提供类似于List&lt;int&gt; 的东西

【讨论】:

  • +1 - 但您可能应该警告某人变异包装的int[] 的陷阱。
  • 此外,OP 的示例实际上可能是“对象拒绝”的情况,他可能真正需要的是特定于域的类而不是通用包装的 int[]
  • +1 到两个 cmets。如果他真的需要一个包装好的int[],他应该使用defensive copy
【解决方案2】:

int[] 数组对象无法知道两个数组是否相等,因为它们实际上只是指针,并且由于它们指向两个不同的数组,因此它们被认为是不相等的。之所以使用指针来比较相等,是因为 Object 类以这种方式定义了最基本的 equals 方法。

您需要创建一个简单的类来封装您的数组。 这是一个任何人都可以理解的简单方法。

class IntArray {
    int[] myArray;
    public IntArray () {
        myArray = new int[0];
    }
    public IntArray (int [] array) {
        myArray = array;
    }
    /**
     * This method is for accessing the array.
     * The array CAN be modified using this method.
     */
    public int[] getArray() {
        return myArray;
    }
    /**
     * Uses built-in hashCode generating method
     * within the Arrays class.
     * Importing java.util.Arrays is necessary.
     */
    public int hashCode() {
        return Arrays.hashCode(myArray);
    }
    public boolean equals(Object o) {
        if (!(o instanceof IntArray))
            return false;

        //Should use Arrays.equals(o.myArray, myArray);

        if (o.myArray.length != myArray.length)
            return false;
        else {
            for (int i = 0; i < myArray.length; i++) {
                if (myArray[i] != o.myArray[i]) {
                    return false;
                }
            }
            return true;
        }
    }
}

完成此操作后,您可以轻松地做一些以前做过的事情:

    Stack<In> myStack = new Stack<int[]>();
    myStack.push( new IntArray (new int[]{1,2}) );
    myStack.push( new IntArray (new int[]{1,3}) );
    myStack.push( new IntArray (new int[]{1,4}) );
    if (myStack.contains( new IntArray (new int[]{1,3})) ) {
        System.out.println("YES");
    } else {
        System.out.println("NO");
    }

那肯定行得通。

【讨论】:

    【解决方案3】:

    要让它打印“YES”,您需要将堆栈设置为已定义 equals()hashCode() 的某个对象,这样具有相同元素的两个数组将被视为相等。

    所以是这样的(这只是划掉了,可能会更好):

    public class ArrayHolder
    {
        private int[] theArray;
    
        public ArrayHolder(int[] theArray) {
           this.theArray = theArray;
        }
    
        public array() {
            return theArray;
        }
    
        public boolean equals(Object o) {
            // Code that will return true if
            // o is an int[] that contains the
            // same elements as this
        }
    
        public int hashCode() {
            // code that will return a hash
            // based on the array elements so
            // that arrays with the same elements
            // will have the same hash
        }
    }
    

    然后让你的Stack 成为Stack&lt;ArrayHolder&gt;

    【讨论】:

      【解决方案4】:

      一种选择是使用包装器,例如

      class ArrayWrapper {
          int[] data;
      
          public boolean equals(Object o) {
              if (o instanceof ArrayWrapper)
                  return Arrays.equals(data, ((ArrayWrapper) o).data);
              return false;
          }
      
          public int hashCode() {
              return Arrays.hashCode(data);
          }
      }
      

      另一个解决方法是覆盖contains,如

      class SmartStack extends Stack<int[]> {
          @Override
          public boolean contains(Object o) {
              ...
          }
      }
      

      【讨论】:

      • SmartStack 是一个非常糟糕的 hack。您确定没有要覆盖的方法了吗?
      • 不,如果我们想确保 Stack 的所有方法安全工作,我们需要重写近十几个方法。所以诚然,这不是一个很好的解决方案。但它确实避免了包装对象或动态列表的开销。如果我在堆栈中有许多数组并且不关心“白痴校对”代码,我可能会这样做。
      【解决方案5】:

      contains() 方法依赖于 equals() 的结果 - 如果你想要完全控制,子类和覆盖 equals() 来表示你想要的。

      【讨论】:

        【解决方案6】:

        首先,您必须定义“包含”的含义。 Stack.contains 的文档说:

        返回:当且仅当指定对象与此向量中的一个组件相同时返回 true,由 equals 方法确定。

        (堆栈扩展向量)

        因此,您可以创建自己的类,该类将整数数组作为实例变量,并在该类上覆盖“等于”以实现在您的情况下意味着什么。只要确保你正确地做到这一点。有关如何做到这一点的信息是everwhere

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-25
          相关资源
          最近更新 更多