2010-05-09 17 views
5

Mam problem z ArrayList. Potrzebuję go do zapisania wyniku. Ponieważ chcę zacząć od elementu n, próbowałem dać ArrayList pojemność z ensureCapacity(n+1), aby użyć set(n,x), ale dostaję IndexOutOfBoundsException.Java ArrayList <Double> Problem IndexOutOfBoundsException

Próbowałem przechowywać n add(x) przed użyciem zestawu i to działa.

Więc chciałbym wiedzieć, dlaczego to nie działa na mojej drodze i jak rozwiązać ten problem, ponieważ put n razy add(x) nie jest dobry styl ;-)

Odpowiedz

6

Jeśli nie lubisz używać własnego pętli i metodę lista add bezpośrednio potem jest inna droga. Stwórz swoją ArrayList z liczbą elementów chcesz go bezpośrednio tak:

final int MAX_ELEMENTS = 1000; 
List<Integer> myList = new ArrayList<Integer>(
    Collections.<Integer>nCopies(MAX_ELEMENTS, null)); 

Albo, jeśli masz już listę, którą chcesz powiększyć rozmiar przez n elementów:

myList.addAll(Collections.<Integer>nCopies(n, null)); 

(Uwaga, założyłem tutaj, że lista będzie zawierała obiekty Integer, ale można to zmienić na niestandardowy typ. Jeśli pracujesz z typami raw/pre-Java 5, po prostu upuść ogólne deklaracje.)

Co do rzeczywistego pytania: pojemność! = Zawartość. ArrayList wewnętrznie ma zarówno tablicę fizyczną, jak i liczbę rzeczywistych elementów. Zwiększenie pojemności, zmienia wewnętrzną tablicę tak, aby mogła pomieścić wiele elementów, jednak liczba nie ulega zmianie. Musisz dodać elementy, aby zwiększyć tę liczbę.

Z drugiej strony, jeśli próbujesz ustawić określone elementy i znasz maksimum, którego chcesz użyć, dlaczego nie użyć bezpośrednio tablicy? Jeśli musisz przekazać tę tablicę do interfejsu API, który ma List s, użyj Arrays.asList. Inne klasy nadal mogą zmieniać zawartość tablicy, ale nie będzie w stanie zwiększyć jej rozmiaru lub pojemności.

7

Po zmianie zdolności ArrayList nie tworzy żadnych elementów, po prostu rezerwuje pamięć tam, gdzie mogą istnieć elementy. Możesz sprawdzić rozmiar przed i po dostosowaniu pojemności, a zobaczysz, że się nie zmienia.

Celem zmiany pojemności jest, jeśli z góry wiesz, ile elementów będziesz mieć, możesz uniknąć niepotrzebnego powtarzania zmian podczas dodawania nowych elementów, a także uniknąć marnotrawienia pamięci z nadmiernej ilości niewykorzystanej pojemności.

0

Otrzymujesz ten wyjątek ponieważ ensureCapacity() tylko upewnia się, że nie ma wystarczającej ilości pamięci przydzielone do dodawania obiektów do ArrayList, wierzę, że to jest w przypadku, gdy chcesz dodać wiele obiektów na raz, bez konieczności przenoszenia pamięć.

Aby zrobić to, co chcesz trzeba by zainicjować ArrayList z elementami zerowymi pierwszych ...

int n = 10; //capacity required 
ArrayList foo = new ArrayList(); 

for(int i=0; i<=n; i++) { 
     foo.add(null); 
} 

Wtedy masz przedmiotów w liście, że można odwoływać przez indeks i wont otrzymywać wyjątek.

0

ensureCapacity() ma inny cel. Powinien być używany w przypadkach, gdy poznasz wymagany rozmiar modelu List po jego skonstruowaniu. Jeśli znasz rozmiar przed konstruktorem, po prostu przekazuj go jako argument do konstruktora.

W pierwszym przypadku należy użyć funkcji ensureCapacity(), aby zapisać wielokrotne kopiowanie tablicy podkładu przy każdym dodaniu. Jednak za pomocą tej metody pozostawia strukturę w pozornie niespójnym stanie

  • wielkość tablicy podkładowej zwiększa
  • pole size na ArrayList nie jest.

ten jest jednak normalne, ponieważ od pojemności = rozmiar

pomocą metody add(..), który jest jedynym, który ma większe pole size:

ArrayList list = new ArrayList(); 
list.ensureCapacity(5); // this can be done with constructing new ArrayList(5) 

for (int i = 0; i < list.size - 1; i ++) { 
    list.add(null); 
} 
list.add(yourObject); 
0

Może powinieneś przemyśleć wybór przy użyciu List<Double>. Możliwe, że bardziej odpowiednie byłoby dodanie elementu w porządku nieparzystym.

Niezależnie od tego, czy jest to odpowiednie, zależy od wiedzy na temat użytkowania, której obecnie nie posiadam.

Czy struktura danych ostatecznie zostanie całkowicie wypełniona, czy też dane są rozrzedzone?

+0

To byłoby najczystsze rozwiązanie, ale ArrayList jest używana jako argument w metodzie, która zajmuje tylko ArrayList. Może gdybym miał wystarczająco dużo czasu, przeładowuję go za pomocą Map. –

+1

Możesz także rozważyć załadowanie mapy, a następnie napisanie metody budowania tablicy ArrayList z zawartości mapy po jej załadowaniu. Ale jeśli naprawdę potrzebujesz ArrayList, rozwiązanie opublikowane przez Bozho może być w porządku. –

+0

"ArrayList jest używana jako argument w metodzie, która pobiera tylko ArrayList" Poważnie? Istnieje kod, który bierze 'ArrayList' zamiast tylko' List'? – Powerlord

0

co inni ludzie mówili o ensureCapacity() ...

trzeba napisać klasę jak DynamicArrayList rozciąga ArrayList. następnie wystarczy przesłonić dodać (n, x), aby zrobić z logiki dla dodania pętli (null) określone.

2

Jak inni odpowiedzieli, ensureCapacity() jest tylko związane z wydajnością, nie jest często używane przez zwykłego użytkownika.

Od Bruce Eckel jest Thinking in Java książki:

w prywatnej wiadomości, Joshua Bloch napisał:”... uważam, że błędnie pozwalające szczegółów realizacji (takich jak tabeli mieszania rozmiar i współczynnik obciążenia) do naszych interfejsów API. Klient powinien podać , być może poda nam maksymalny oczekiwany rozmiar kolekcji , a my powinniśmy zabrać go stamtąd .. Klienci mogą łatwo zrobić więcej szkody niż pożytku, wybierając wartości dla tych parametrów. Jako ekstremalny przykład, na przykład , należy rozważyć zwiększenie pojemności o wartości . Nikt nigdy nie powinien ustawić tego jako i nie powinniśmy mieć pod warunkiem, że jest to . Jeśli ustawisz tę wartość na dowolną wartość zerową , koszt asymptotyczny sekwencja dodatków przechodzi od liniowej do kwadratowej. Innymi słowy, to niszczy twoją wydajność. Z biegiem czasu, zaczynamy rozmyślać na temat tego coś w rodzaju. Jeśli spojrzeć na IdentityHashMap, zobaczysz, że nie posiada parametrów strojenia niskopoziomowe”