Am Dienstag, den 9. März 2010 um 03:02 Uhr schrieb Kevin L. Stern:
Ich habe eine schnelle Suche durchgeführt und es scheint, dass Java tatsächlich auf zwei Komplementen basiert. Gestatten Sie mir dennoch, darauf hinzuweisen, dass mich diese Art von Code im Allgemeinen beunruhigt, da ich davon ausgehe, dass irgendwann jemand vorbeikommt und genau das tut, was Dmytro vorgeschlagen hat. das heißt, jemand wird sich ändern:
if (a - b > 0)
zu
if (a > b)
und das ganze Schiff wird sinken. Ich persönlich möchte Unklarheiten vermeiden, z. B. den Überlauf von Ganzzahlen zu einer wesentlichen Grundlage für meinen Algorithmus zu machen, es sei denn, es gibt einen guten Grund dafür. Im Allgemeinen würde ich es vorziehen, einen Überlauf insgesamt zu vermeiden und das Überlaufszenario deutlicher zu machen:
if (oldCapacity > RESIZE_OVERFLOW_THRESHOLD) {
// Do something
} else {
// Do something else
}
Das ist ein guter Punkt.
In können ArrayList
wir das nicht (oder zumindest nicht kompatibel) machen, weil
ensureCapacity
es sich um eine öffentliche API handelt und negative Zahlen effektiv bereits als Anforderungen für eine positive Kapazität akzeptiert, die nicht erfüllt werden kann.
Die aktuelle API wird folgendermaßen verwendet:
int newcount = count + len;
ensureCapacity(newcount);
Wenn Sie einen Überlauf vermeiden möchten, müssen Sie zu etwas weniger Natürlichem wechseln
ensureCapacity(count, len);
int newcount = count + len;
Wie auch immer, ich behalte den überlaufbewussten Code bei, füge aber weitere Warnkommentare hinzu und "skizziere" die Erstellung riesiger Arrays, sodass der
ArrayList
Code jetzt wie folgt aussieht:
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
modCount++;
// Overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// Overflow-conscious code
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 int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
Webrev regeneriert.
Martin
if (newCapacity - minCapacity < 0)
besser alsif (newCapacity < minCapacity)
Überlauf zu verhindern?