Подтвердить что ты не робот

Нежелательное поведение ArrayList remove() в Java

У меня следующие два сценария:

1. int как параметр

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 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

Я передаю 2 как значение в обоих случаях, но я получаю другое значение в List. Какова фактическая причина такого поведения?

Правильное удаление целого из списка не объясняет, что тип данных встроенного типа имеет такое же значение, но имеет поведение по-другому, как указано выше

4b9b3361

Ответ 1

Autoboxing

Метод list.remove перегружен, а две разные подписи используются для разных целей. Один, list.remove(int), удаляет элемент на основе его индекса, а другой, list.remove(Object), удаляет элемент на основе равенства объекта. Ваша первая ситуация запускает первый тип, а ваш второй пример (с помощью long longNum) запускает второй тип, autoboxing примитив long для объекта java.lang.Long. Это не равно значениям java.lang.Integer (autoboxed), добавленным в список, и, следовательно, не будет удалять что-либо из списка, и размер останется таким же.

Ответ 2

Из документа List.remove() :

remove (int index) Удаляет элемент в указанной позиции в этот список (дополнительная операция).

remove (Object o) Удаляет первое вхождение указанного элемента из этого списка, если он присутствует (дополнительная операция).

removeAll (коллекция c) Удаляет из этого списка все его элементы которые содержатся в указанной коллекции (дополнительная операция).

Если второй пример действительно длинный, он не будет удален (так как он использует второй метод удаления).

Ответ 3

Будьте осторожны: первый удаляет Integer в index = 2. См. ArrayList.remove(int)

Второй пытается удалить объект с ArrayList.remove(Object), но объект, который вы хотите удалить, не существует, потому что это объект Long.

Ответ 4

Интерфейс List содержит два метода remove() - remove(Object) и remove(int).

Реализация remove(Object) в Java 6 выглядит следующим образом:

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;
}

Реализация remove(int) в Java 6:

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;
}

В первом примере вы на самом деле вызываете метод remove(int), который удаляет объект по указанному индексу. В этом случае вы указали индекс 2, который на самом деле является значением "3".

В вашем втором примере вы вызываете метод remove(Object), так как не существует метода remove(long), а long не будет преобразован в int. Основываясь на реализации метода remove(Object), он ищет равенство объектов. Поскольку ваш список содержит объекты типа Integer, и вы предоставляете long, ничто не будет соответствовать ему.

Следующий метод, вероятно, лучший пример того, что происходит:

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);
}

Вывод этого кода:

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

Ответ 5

Когда вы делали list.remove(intNum);, он выполнял подпись remove(int index); класса List, которая удаляет элемент данного индекса.

Однако, когда вы сделали list.remove(longNum); (учитывая, что вы имели в виду longNum как long), он выполнил подпись boolean remove(Object o); класса List, которая проверяет, присутствует ли объект в списке, и если да удаляет его.

Поскольку список представляет собой список Integer, он не смог найти объект и ничего не удалял, поэтому второй результат равен 3, ничего не удалено.

Ответ 6

Вызов List.remove() с аргументом int будет соответствовать сигнатуре remove(int index), а элемент в индексе list[2] будет удален независимо от того, имеет ли список объект Integer со значением 2.

Вызов List.remove() с длинным аргументом заставит компилятор делать автоматический бокс в объект Long и соответствовать сигнатуре remove(Object o). Список будет итерировать, спрашивая, являются ли o.equals(каждый элемент) и как было упомянуто ранее, Long не равно Integer.

Ответ 7

Список в коллекции имеет два перегруженных метода 1. public E remove (int index) 2. public boolean remove (Object o)

В вашем случае вызывается второй метод. так как вы проходите длинный (неявное приведение к длинному оберточному классу класса Object).

Теперь List.remove(longNum) удаляет элемент с самым низким индексом я таким образом, что (longNum == null? get (i) == null: longNum.equals(get (i))) (если такой элемент существует).

Теперь в вашем случае, когда счетчик пришел во вторую позицию (т.е. я = 1). longNum.equals(get (1)) возвращает false, потому что get (1) возвращает объект java.lang.Integer со значением = 2 и longNum является экземпляром java.lang.Long со значением = 2. Таким образом, метод equals возвращает false, поэтому он не удаляет элемент.

Вы можете проверить тип значения по его классу Name

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