Jak mogę wyciąć ArrayList z ArrayList w Javie?


80

Jak uzyskać wycinek tablicy ArrayListw języku Java? W szczególności chcę zrobić coś takiego:

ArrayList<Integer> inputA = input.subList(0, input.size()/2);
// where 'input' is a prepouplated ArrayList<Integer>

Spodziewałem się więc, że to zadziała, ale Java zwraca List- więc jest niezgodny. A kiedy próbuję to przesłać, Java mi na to nie pozwala. Potrzebuję ArrayList- co mogę zrobić?


4
Dlaczego nalegasz na używanie ArrayList? Myślę, że możesz nie rozumieć, jak działają interfejsy, ponieważ Listi ArrayListnie są „niekompatybilne” - ArrayListimplementują Listi Listprawdopodobnie zawierają wszystkie niezbędne metody, których potrzebujesz.
Bombe

2
Nalegam na używanie ArrayList, ponieważ jest to pytanie dotyczące podglądu ze sztywnym prototypem metody. Wyraźnie brakuje mi zrozumienia, ponieważ subList ma zwrócić typ listy, a mimo to nie mogę rzutować zwróconej listy na ArrayList. Więc powiedz mi stary ...
BT,

4
Jest całkowicie możliwe, że potrzebuje on, ArrayListponieważ następnie musi wywołać za jego pomocą metodę, która akceptuje rozszerzenie ArrayList. Prawdopodobnie taka metoda jest źle zaprojektowana i należy ją Listzamiast tego zaakceptować , ale takie sytuacje mogą pojawić się nie tylko w pytaniach podczas rozmowy kwalifikacyjnej, ale w kodzie napisanym przez innych, którego nie można po prostu przejść i zmienić. Współpracownicy i biblioteki nie zawsze są idealne.
Gravity

Odpowiedzi:


124

W Javie dobrą praktyką jest używanie typów interfejsów zamiast konkretnych klas w API.

Twoim problemem jest to, że używasz ArrayList(prawdopodobnie w wielu miejscach) miejsca, w którym naprawdę powinieneś używać List. W rezultacie stworzyłeś sobie problemy z niepotrzebnym ograniczeniem, że lista jest ArrayList.

Oto jak powinien wyglądać Twój kod:

List input = new ArrayList(...);

public void doSomething(List input) {
   List inputA = input.subList(0, input.size()/2);
   ...
}

this.doSomething(input);

Twoje proponowane „rozwiązanie” problemu było następujące:

new ArrayList(input.subList(0, input.size()/2))

Działa to poprzez utworzenie kopii podlisty. To nie jest plasterek w normalnym sensie. Ponadto, jeśli podlista jest duża, wykonanie kopii będzie kosztowne.


Jeśli są ograniczane przez API, że nie można zmienić , tak że trzeba zadeklarować inputAjako ArrayList, może być w stanie realizować niestandardową podklasę ArrayList, w których subListmetoda zwraca podklasę ArrayList. Jednak:

  1. Zaprojektowanie, wdrożenie i przetestowanie wymagałoby dużo pracy.
  2. Dodałeś teraz znaczącą nową klasę do swojego kodu, prawdopodobnie z zależnościami od nieudokumentowanych aspektów (a zatem „podlegających zmianom”) aspektów ArrayListklasy.
  3. Musisz zmienić odpowiednie miejsca w bazie kodu, w których tworzysz ArrayListinstancje, aby zamiast tego tworzyć instancje swojej podklasy.

Rozwiązanie „kopiuj tablicę” jest bardziej praktyczne… biorąc pod uwagę, że nie są to prawdziwe wycinki.


6
W rzeczywistości subList nie kopiuje; zwraca widok do oryginalnej listy ( docs.oracle.com/javase/6/docs/api/java/util/… )
Matt

3
Właściwie @Matthew, mam na myśli odpowiedź własną OP, w której robi to:new ArrayList(input.subList(0, input.size()/2))
Stephen C,

1
+1 dla tej frazy: w Javie dobrą praktyką jest używanie typów interfejsów zamiast konkretnych klas w API.
Ilonpilaaja

6

Znalazłem sposób, jeśli znasz startIndex i endIndex elementów, które należy usunąć z ArrayList

Pozwolić albyć przy ArrayList i startIndex, endIndexbyć początek i wskaźnik końca być usunięte z tablicy, odpowiednio:

al.subList(startIndex, endIndex + 1).clear();

6

Jeśli nie ma istniejącej metody, myślę, że możesz iterować od 0 do input.size()/2, biorąc każdy kolejny element i dołączając go do nowej ArrayList.

EDYCJA : Właściwie myślę, że możesz wziąć tę Listę i użyć jej do utworzenia wystąpienia nowej ArrayList przy użyciu jednego z konstruktorów ArrayList .


2
Dokładnie to zrobiłem (zamieściłem moją odpowiedź, zanim przeczytałem twoją edycję). Dzięki
:)

Ale to kopiuje List, aby utworzyć nową ArrayList.
Joren

2
@BT - Dla przypomnienia, nie to zwykle oznacza termin „plasterek” w tym kontekście.
Stephen C


-4

Tak to rozwiązałem. Zapomniałem, że podlista była bezpośrednim odniesieniem do elementów z oryginalnej listy, więc ma sens, dlaczego nie działa.

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.