2015-05-20 13 views
19

I dwóch następujących scenariuszy:Niepożądane zachowanie ArrayList usunąć() Java

1. Int wartość jako parametr

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. długo jak wartość parametru

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 

Przepuszczam 2 jako wartość w obu przypadkach, ale otrzymuję inną wartość wielkości listy. Jaki jest faktyczny powód takiego zachowania?

Properly removing an Integer from a List nie wyjaśnia o wbudowany typ danych posiadające tę samą wartość, ale o zachowanie inaczej jak poprosił powyżej

+0

Teraz widać, że list.remove (2) usuwa element z indeksem 2, a nie całkowitą 2, należy dokonać wskaż jawnie rzutować na "int" lub "Integer" lub ryzykujesz tylko wprowadzeniem w błąd. – Neil

+0

To może być miłe pytanie do wywiadu technicznego. – beetstra

Odpowiedz

24

autoboxing

Sposób list.remove jest przeciążony, i dwa różne podpisy są wykorzystywane do różnych celów. Jeden, list.remove(int), usuwa element na podstawie jego indeksu, a drugi, list.remove(Object), usuwa element na podstawie równości obiektu. Twoja pierwsza sytuacja wyzwala pierwszy typ, a twój drugi przykład (z long longNum) wyzwala drugi typ, powodując autoblokowanie prymitywu long do obiektu java.lang.Long. Nie jest to równe wartościom dodanym do listy, a zatem nie usunie niczego z listy, a rozmiar pozostanie taki sam.

+7

A powodem przeciążenia obiektu "Object" w drugim przypadku jest to, że 'long' nie może zostać przekonwertowane na' int'. Przeciążenie obiektu jest jedynym możliwym do zastosowania, – Arkadiy

+1

Nawet jeśli pierwsza sytuacja wywołała drugi typ, wynik byłby inny. – xehpuk

5

Z List.remove() documentation:

remove (int index) Usuwa element w określonej pozycji na tej liście (operacja opcjonalna).

remove (Obiekt o) Usuwa pierwsze wystąpienie określonego elementu z tej listy, jeśli jest obecne (operacja opcjonalna).

removeAll (Collection c) Usuwa z tej listy wszystkie jej elementy , które znajdują się w określonej kolekcji (operacja opcjonalna).

Jeśli drugi przykład jest rzeczywiście długi, nie zostanie usunięty (ponieważ używa drugiej metody usuwania).

4

Interfejs List zawiera dwie metody: -i remove(int).

Realizacja remove(Object) w Javie 6 jest następująca:

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

Realizacja remove(int) w Javie 6 jest:

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

W pierwszym przykładzie, jesteś rzeczywiście wywołanie remove(int) metoda, która usuwa obiekt z określonego indeksu. W tym przypadku określono indeks 2, który w rzeczywistości jest wartością "3".

W drugim przykładzie, jesteś wywołanie metody remove(Object), ponieważ nie jest to metoda remove(long) i long nie zostanie przekształcony w int. W oparciu o implementację metody remove(Object), szuka równości obiektów. Ponieważ twoja lista zawiera obiekty typu Integer i podajesz Long, nic jej nie dorówna.

Poniższa metoda jest chyba lepszym przykładem tego, co się dzieje:

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

Wyjście z tego kodu jest:

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

Podczas wykonywania list.remove(intNum); wykonywał on podpis remove(int index); klasy List, który usuwa element z danego indeksu.

Jednak kiedy zrobiłeś list.remove(longNum); (biorąc pod uwagę chodziło longNum być long), to wykonał boolean remove(Object o); podpis List klasy, który sprawdza, czy obiekt jest obecny na liście, a jeśli tak, usuwa go.

Ponieważ lista jest na liście Integer, nie może znaleźć obiektu i niczego nie usunięto, dlatego drugi wynik to 3, nic nie jest usuwane.

2

Wywołanie List.remove() z argumentem int będzie pasować do podpisu remove(int index) i pozycję na indeksie list[2] zostaną usunięte niezależnie od tego czy lista zawiera pozycję całkowitą o wartości 2.

Wywołanie List.remove () z długim argumentem spowoduje, że kompilator wykona auto-boxing do obiektu Long i dopasuje podpis remove(Object o). Lista będzie iterować, pytając, czy o.equals (każdy element) i jak wspomniano wcześniej, Long nie jest równy Integer.

2

Lista w kolekcji ma dwie przeciążone metody 1. publiczny E remove (int index) 2. public boolean remove (Object o)

w Twoim przypadku drugiej metodzie zostanie wywołany. ponieważ przechodzisz długo (domyślne rzutowanie na długie opakowanie klasa, więc klasa Object).

Teraz List.remove (longNum) usuwa element o najniższym indeksie i tak, że (longNum == null? Get (i) == null: longNum.equals (get (i))) (jeśli taki element istnieje).

Teraz w Twoim przypadku, gdy licznik wszedł na drugą pozycję (tj. I = 1). longNum.equals (get (1)) zwraca false ponieważ get (1) zwraca Object obiektu java.lang.Integer o wartości = 2, a longNum to instancja java.lang.Long o wartości = 2. Metoda równości zwraca false, więc nie usuwa elementu.

Można sprawdzić typ wartości przez jego nazwa klasy

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