簡體   English   中英

Java ArrayList <Double> IndexOutOfBoundsException問題

[英]Java ArrayList<Double> IndexOutOfBoundsException Problem

我有一個ArrayList的問題。 我需要它來存儲結果。 因為我想從元素n開始,我試圖給ArrayList一個帶有ensureCapacity(n+1)的容量來使用set(n,x)但是我得到一個IndexOutOfBoundsException

我嘗試在使用set之前存儲n add(x) ,這是有效的。

所以我想知道為什么它在我的路上不起作用以及如何解決這個因為把n次add(x)不是一個好的風格;-)

當您更改ArrayList的容量時,它不會創建任何元素,它只會保留可能存在元素的內存。 您可以在調整容量之前和之后檢查尺寸,您會發現它沒有變化。

更改容量的目的是,如果您事先知道您將擁有多少元素,那么您可以在添加新元素時避免不必要的重復調整大小,並且可以避免因未使用的容量過多而浪費內存。

如果您不喜歡直接使用自己的循環和列表add方法,那么還有另一種方法。 使用您想要的元素數創建您的ArrayList ,如下所示:

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

或者,如果您已經有一個列表要擴展n元素的大小:

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

(注意,我在這里假設列表將包含Integer對象,但您可以將其更改為自定義類型。如果您使用的是raw / pre-Java 5類型,則只需刪除泛型聲明。)

至於你的實際問題:容量!=內容。 ArrayList內部同時具有物理數組和實際數據。 增加容量,更改內部數組,以便它可以容納那么多元素,但是,計數不會改變。 您需要添加元素以增加計數。

另一方面,如果您只是嘗試設置特定元素並知道要使用的最大值,為什么不直接使用數組? 如果您需要將此數組傳遞給采用List的API,則使用Arrays.asList 其他類仍然可以更改后備陣列的內容,但它無法增加它的大小或容量。

正如其他人已經回答的那樣, ensureCapacity()只與性能有關,並不是普通用戶經常使用的。

來自Bruce Eckel的Thinking in Java書籍:

在私人消息中,Joshua Bloch寫道:“...我認為我們錯誤地將實現細節(例如散列表大小和加載因子)放入我們的API中。客戶端應該告訴我們集合的最大預期大小,我們應該從那里開始。通過選擇這些參數的值,客戶很容易弊大於利。作為一個極端的例子,考慮Vector的capacityIncrement。沒有人應該設置這個,我們不應該提供它。如果你將它設置為任何非零值,一系列附加的漸近成本從線性到二次。換句話說,它會破壞你的表現。隨着時間的推移,我們開始明智地對待這類事情。如果你看看IdentityHashMap,你會發現它沒有低級調整參數“

您正在獲得此異常,因為ensureCapacity()僅確保分配足夠的內存以將對象添加到ArrayList,我相信這是為了您想要一次添加多個對象,而無需重新定位內存。

要做你想做的事,你必須先用null元素啟動ArrayList ...

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

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

然后,List中有對象可以通過索引引用,並且不會收到異常。

ensureCapacity()有另一個目的。 它應該用於在構建List之后了解List所需大小的情況。 如果你知道構造函數之前的大小,只需將它作為參數傳遞給構造函數。

在前一種情況下,使用ensureCapacity()可以在每次添加時保存后備陣列的多次復制。 但是,使用該方法會使結構處於看似不一致的狀態

  • 后備陣列的大小增加
  • ArrayList上的size字段不是。

然而,這是正常的,因為容量!=大小

使用add(..)方法,這是增加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);

也許您應該重新考慮使用List<Double>的選擇。 如果要以奇數順序添加元素,那么Map<Integer,Double>可能更合適。

這是否合適取決於您目前沒有使用的有關您的使用情況的知識。

數據結構最終會被完全填充,還是數據稀疏?

其他人對EnsureCapacity()的評價......

你應該寫一個像DynamicArrayList extends ArrayList這樣的類。 然后只需覆蓋add(n,x)來處理指定的for循環add(null)邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM