简体   繁体   中英

ArrayList not removing object

The Remove statement is not removing the object. I can see the list size as 2 before & after remove statement.

public class Test {
    private static class Point {
        private int x, y;
        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public static void main(final String[] args) {
        List<Point> pList = new ArrayList<>();
        pList.add(new Point(1, 2));
        pList.add(new Point(3, 4));
        System.out.println(pList.size());
        pList.remove(new Point(3, 4));
    }
}

You Point class does not override the equals method, which the remove method will use to determine whether or not the item is in the list. If you save your new Point(3,4) value into a local variable it will be removed because it is identity equal. Or you can override equals and hashcode .

As @sam points out, here's an example with hashCode and equals:

public class Test {
  private static class Point {
    private int x, y;

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

    @Override
    public int hashCode() {
      return x * y;
    }

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

  public static void main(final String[] args) {
    List<Point> pList = new ArrayList<>();
    pList.add(new Point(1, 2));
    pList.add(new Point(3, 4));
    System.out.println(pList.size());
    pList.remove(new Point(3, 4));
    System.out.println(pList.size());
  }
}

You need to override both equals and hashcode methods.

  @Override
  public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      Point point = (Point) o;
      return x == point.x && y == point.y;
   }
   
   @Override
   public int hashCode() {
      return Objects.hash(x, y);
   }   

Refer to https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#remove(java.lang.Object) for the expected behavior of ArrayList.remove(). The two incarnations of "new Point(3, 4)" create different objects on the heap so they have different references, and since the Point class does not override the equals method, the comparison does not find a match.

The remove method will have the behavior you expect if either you have

    Point p = new Point(3, 4);
    pList.add(p);
    pList.remove(p);

or you override the equals method in the class Point with something like:

    @Override
    public boolean equals(Object other) {
        if (other == null) return false;
        if (this == other) return true;
        if (!(other instanceof Point)) return false;
        Point otherPoint = (Point) other;
        return x == otherPoint.x && y == otherPoint.y;
    }

See also: https://www.geeksforgeeks.org/equals-hashcode-methods-java/

Although technically your question already has correct answers, I'd like to add some explanation.

Your program creates three Point instances (using new Point(...) ) in the following lines:

  public static void main(final String[] args) {
    List<Point> pList = new ArrayList<>();
    pList.add(new Point(1, 2));       // <-- Here is the first one
    pList.add(new Point(3, 4));       // <-- Here is the second one
    System.out.println(pList.size());
    pList.remove(new Point(3, 4));    // <-- Here is the third one
    System.out.println(pList.size());
  }

The second and third happen to have the same x and y values, but that isn't enough for Java's library functions to understand that they are equal in whatever sense. Per se, two instances are only equal if they are actually two references to the very same instance (eg if you saved your second Point to a local variable and used that for the removal).

With your code, trying to remove the third Point finds out that (exactly) this Point isn't on the list, and does nothing.

But you can write an equals() method in your Point class where you define, under which circumstances you want two different Point s to be regarded as equal. You'd typically have this method compare x and y .

Examples can be seen in other answers. Or, if you use an IDE like Eclipse, you'll find a function named "create hashCode() and equals()" that writes a perfect equals() method for you, including all the corner cases that one might casually forget to cover.

WTF is hashCode() ? To support different data structures besides ArrayList (eg HashMap ), a specific equals() method should always be accompanied by a matching hashCode() method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM