Undesired behavior of ArrayList remove() in Java [duplicate]

六月ゝ 毕业季﹏ 提交于 2020-02-03 03:54:30

问题


I have following two scenarios:

1. int value as parameter

int intNum = 2;
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.remove(intNum);
System.out.println(list.size());
// output: 2

2. long value as parameter

long longNum = 2;
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.remove(longNum);
System.out.println(list.size());
// output: 3

I am passing 2 as the value in both cases, but I am getting a different size value of the List. What is the actual reason for this behavior?

Properly removing an Integer from a List does not explain about build-in data type having same value but having behavior differently as asked above


回答1:


Autoboxing

The list.remove method is overloaded, and the two different signatures are used for different purposes. One, list.remove(int), removes an item based on its index, and the other one, list.remove(Object), removes an item based on object equality. Your first situation triggers the first type, and your second example (with a long longNum), triggers the second type, autoboxing the long primitive to a java.lang.Long object. This is not equal to the java.lang.Integer (autoboxed) values added to the list, and thus will not remove anything from the list and the size will remain same.




回答2:


From the List.remove() documentation :

remove(int index) Removes the element at the specified position in this list (optional operation).

remove(Object o) Removes the first occurrence of the specified element from this list, if it is present (optional operation).

removeAll(Collection c) Removes from this list all of its elements that are contained in the specified collection (optional operation).

If you second example is indeed a long, it won't be removed (since it uses the second remove method).




回答3:


Be careful: The first one removes the Integer at index = 2. See ArrayList.remove(int)

The second one tries to remove an object with ArrayList.remove(Object), but the object you want to remove does not exist because it's a Long object.




回答4:


The List interface contains two remove() methods - remove(Object) and remove(int).

The implementation of remove(Object) in Java 6 is as follows:

public boolean remove(Object o) {
if (o == null) {
        for (int index = 0; index < size; index++)
    if (elementData[index] == null) {
        fastRemove(index);
        return true;
    }
} else {
    for (int index = 0; index < size; index++)
    if (o.equals(elementData[index])) {
        fastRemove(index);
        return true;
    }
    }
return false;
}

The implementation of remove(int) in Java 6 is:

public E remove(int index) {
RangeCheck(index);

modCount++;
E oldValue = (E) elementData[index];

int numMoved = size - index - 1;
if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
elementData[--size] = null; // Let gc do its work

return oldValue;
}

In your first example, you're actually calling the remove(int) method, which removes the object at the specified index. In this case, you specified index 2, which is actually the value "3".

In your second example, you're calling the remove(Object) method, since there isn't a remove(long) method and a long won't be converted into an int. Based on the implementation of the remove(Object) method, it looks for object equality. Since your list contains objects of type Integer and you're providing a Long, nothing will match it.

The following method is probably a better example of what's happening:

public static void main(String[] args) {
    ArrayList<Integer> list;

    System.out.println("Removing intNum");
    int intNum = 2;
    list = new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    list.add(3);
    System.out.println("List = " + list);
    list.remove(intNum);
    System.out.println("List = " + list);

    System.out.println("Removing longNum");
    long longNum = 2;
    list = new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    list.add(3);
    System.out.println("List = " + list);
    list.remove(longNum);
    System.out.println("List = " + list);
}

The output of this code is:

Removing intNum
List = [1, 2, 3]
List = [1, 2]
Removing longNum
List = [1, 2, 3]
List = [1, 2, 3]



回答5:


Calling List.remove() with an int argument will match the signature remove(int index) and the item on index list[2] will be removed regardless if the list has an Integer item with value of 2.

Calling List.remove() with an long argument will cause the compiler to do auto-boxing into a Long object and match the signature remove(Object o). The list will iterate, asking if o.equals(each item) and as was mentioned before, Long does not equal Integer.




回答6:


When you were doing list.remove(intNum); it was performing the remove(int index); signature of the List class, which remove the item of the given index.

However when you did list.remove(longNum); (considering you meant longNum to be long), it performed the boolean remove(Object o); signature of List class, which checks if the object is present in the list, and if yes removes it.

Since the list is an Integer list it could not find the object and did not remove anything, and that is why the second result is 3, nothing is deleted.




回答7:


List in Collection has two overloaded methods 1. public E remove(int index) 2. public boolean remove(Object o)

In your case second method gets called. since you are passing long (implicit casting to Long wrapper class so Object class ).

Now List.remove(longNum) removes the element with the lowest index i such that (longNum==null ? get(i)==null : longNum.equals(get(i) ) ) (if such an element exists).

Now in Your case when the counter came at second position (i.e i=1). longNum.equals(get(1)) returns false because get(1) returns the Object of java.lang.Integer with value=2 and longNum is an instance of java.lang.Long with value=2. So equals method returns false thus it does not delete the element.

You can check the type of the value by its class Name

   System.out.println(" Element Value :"+list.get(1));
   System.out.println(" Element Class :"+list.get(1).getClass());


来源:https://stackoverflow.com/questions/30349653/undesired-behavior-of-arraylist-remove-in-java

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!