2011-12-19 49 views
3

JDK 7 java.util.ArrayList類中的引用代碼段令我感到困惑。我不能爲我的生活理解它怎麼可能導致溢出。我很困惑的區域用<--- what do they mean by this?標記。有人能幫助我理解這種邏輯可能溢出的情況嗎? TIA。在Java中調整ArrayList的大小時,無法理解溢出的可能性

public void ensureCapacity(int minCapacity) { 
    if (minCapacity > 0) 
     ensureCapacityInternal(minCapacity); 
} 

private void ensureCapacityInternal(int minCapacity) { 
    modCount++; 
    // overflow-conscious code <--- what do they mean by this? 
    if (minCapacity - elementData.length > 0) 
     grow(minCapacity); 
} 

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 

private void grow(int minCapacity) { 
    // overflow-conscious code <--- what do they mean by this? 
    int oldCapacity = elementData.length; 
    int newCapacity = oldCapacity + (oldCapacity >> 1); 
    if (newCapacity - minCapacity < 0) 
     newCapacity = minCapacity; 
    if (newCapacity - MAX_ARRAY_SIZE > 0) 
     newCapacity = hugeCapacity(minCapacity); 
    // minCapacity is usually close to size, so this is a win: 
    elementData = Arrays.copyOf(elementData, newCapacity); 
} 

private static int hugeCapacity(int minCapacity) { 
    if (minCapacity < 0) // overflow <--- what do they mean by this? 
     throw new OutOfMemoryError(); 
    return (minCapacity > MAX_ARRAY_SIZE) ? 
     Integer.MAX_VALUE : 
     MAX_ARRAY_SIZE; 
} 

編輯:我主要關心的是:hugeCapacity如何能夠獲得負尺寸?

+0

如果您對Java代碼中的註釋感興趣,它不是「堆棧溢出」溢出。它關於內部陣列的管理容量。 – 2011-12-19 06:30:42

+0

@jowierun:你說得對,堆棧溢出不是我關心的地方。我很確定這些評論說的是數據類型溢出/容量溢出。 'hugeCapacity()'方法中的新'OutOfMemoryError()'會讓我感到困惑。 – sasuke 2011-12-19 06:35:50

回答

1

OutOfMemoryError()(在ArrayList)拋出2個條件:

  1. minCapacity是小於零。這意味着無法創建存儲器陣列分配,即elementData陣列大小不能小於零。
  2. 該陣列的容量超出了虛擬機內存堆空間。虛擬機無法創建內存(grow())在陣列中分配更多對象。

因此爲什麼hugeCapacity()確保安全地分配內存。


grow()hugeCapacity()只內ensureCapacityInternal()使用,因此可以說,minCapacity < 0是不必要的。我相信這是一個安全檢查,只是爲了使陣列的安全性增加。任何差異性,而不是拋出錯誤。

+0

也許我不清楚,但考慮到'public ensureCapacity'方法中已經檢查了'capacity> 0',那麼'minCapacity'如何小於0? – sasuke 2011-12-19 06:46:31

+0

+1,感謝您的回覆。我一直在努力(玩弄值),以確保控制進入minCapacity <0塊,但不能想到任何可能發生的情況。不知道爲什麼檢查到位... – sasuke 2011-12-19 07:12:52

2

當計算值大於其類型所允許的字節數時,會產生溢出結果。

oldCapacity執行了一些操作後,如果將這些操作的值賦給newCapacity,如果這些操作的結果爲某個值不適合int,則會發生溢出。我想這就是爲什麼這個代碼被評論爲溢出代碼。

+0

好的,要點。但爲什麼'hugeCapacity()'方法必須檢查容量<0? hugeCapacity會收到負值的情況是什麼? – sasuke 2011-12-19 06:38:10

+1

我還沒有完成完整的代碼,對不起,但是minCapacity可以小於零。例如,如果對minCapacity執行了一些計算,結果會更高,那麼它可以轉換爲minCapacity。所以java會放棄一些高階位來使它適合int。這樣做時,符號位可能會打開。從而使其成爲負值。 @sasuke – Zohaib 2011-12-19 07:25:19

+0

但是不應該檢查size> 0的公共方法'ensureCapacity'(按照我的問題發佈的代碼)過濾出這種情況嗎? – sasuke 2011-12-19 07:30:34

0

我懷疑這段代碼可能在某些時候被修改過與array.length是long的數組一起工作。 (當然,那是不正規的Java ......就像我們知道的那樣)。

0

我發現minCapacity < 0的情況。假設有兩個長尺寸ArrayLists,當你將一個添加到另一個時,size + numNew將會溢出。

public boolean addAll(Collection<? extends E> c) { 
    Object[] a = c.toArray(); 
    int numNew = a.length; 
    ensureCapacityInternal(size + numNew); // Increments modCount 
    System.arraycopy(a, 0, elementData, size, numNew); 
    size += numNew; 
    return numNew != 0; 
} 

例如,下面的代碼會拋出一個OutOfMemoryError。

int oneSize = Integer.MAX_VALUE - 16; 
int twoSize = oneSize >> 1; 
List<Byte> one = new ArrayList<>(oneSize); 
for (int i = 0; i < oneSize; i++) { 
    one.add((byte) 1); 
} 
List<Byte> two = new ArrayList<>(twoSize); 
for (int i = 0; i < twoSize; i++) { 
    two.add((byte) 2); 
} 

one.addAll(two); 
相關問題