< prev index next >
src/java.base/share/classes/java/lang/AbstractStringBuilder.java
Print this page
@@ -68,10 +68,15 @@
* The count is the number of characters used.
*/
int count;
/**
+ * Whether value array is shared with a String.
+ */
+ transient boolean shared;
+
+ /**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
@@ -86,10 +91,19 @@
value = StringUTF16.newBytesFor(capacity);
coder = UTF16;
}
}
+ byte[] unshareValue() {
+ if (shared) {
+ // assert (count << coder) == value.length
+ value = Arrays.copyOf(value, value.length);
+ shared = false;
+ }
+ return value;
+ }
+
/**
* Returns the length (character count).
*
* @return the length of the sequence of characters currently
* represented by this object
@@ -164,10 +178,11 @@
throw new OutOfMemoryError();
}
newCapacity = StringUTF16.MAX_LENGTH;
}
this.value = Arrays.copyOf(value, newCapacity << coder);
+ this.shared = false;
}
/**
* If the coder is "isLatin1", this inflates the internal 8-bit storage
* to 16-bit <hi=0, low> pair storage.
@@ -178,10 +193,11 @@
}
byte[] buf = StringUTF16.newBytesFor(value.length);
StringLatin1.inflateSB(value, buf, 0, count);
this.value = buf;
this.coder = UTF16;
+ this.shared = false;
}
/**
* Attempts to reduce storage used for the character sequence.
* If the buffer is larger than necessary to hold its current sequence of
@@ -223,17 +239,19 @@
*/
public void setLength(int newLength) {
if (newLength < 0) {
throw new StringIndexOutOfBoundsException(newLength);
}
- ensureCapacityInternal(newLength);
if (count < newLength) {
+ ensureCapacityInternal(newLength);
if (isLatin1()) {
StringLatin1.fillNull(value, count, newLength);
} else {
StringUTF16.fillNull(value, count, newLength);
}
+ } else if (newLength < count) {
+ unshareValue();
}
count = newLength;
}
/**
@@ -435,14 +453,17 @@
* negative or greater than or equal to {@code length()}.
*/
public void setCharAt(int index, char ch) {
checkIndex(index, count);
if (isLatin1() && StringLatin1.canEncode(ch)) {
+ final byte[] value = unshareValue();
value[index] = (byte)ch;
} else {
if (isLatin1()) {
inflate();
+ } else {
+ unshareValue();
}
StringUTF16.putCharSB(value, index, ch);
}
}
@@ -824,10 +845,11 @@
end = count;
}
checkRangeSIOOBE(start, end, count);
int len = end - start;
if (len > 0) {
+ unshareValue();
shift(end, -len);
count -= len;
}
return this;
}
@@ -875,10 +897,11 @@
* is negative or greater than or equal to
* {@code length()}.
*/
public AbstractStringBuilder deleteCharAt(int index) {
checkIndex(index, count);
+ unshareValue();
shift(index + 1, -1);
count--;
return this;
}
@@ -907,10 +930,11 @@
}
checkRangeSIOOBE(start, end, count);
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount);
+ unshareValue();
shift(end, newCount - count);
count = newCount;
putStringAt(start, str);
return this;
}
@@ -1463,11 +1487,11 @@
* a valid surrogate pair.
*
* @return a reference to this object.
*/
public AbstractStringBuilder reverse() {
- byte[] val = this.value;
+ byte[] val = unshareValue();
int count = this.count;
int coder = this.coder;
int n = count - 1;
if (COMPACT_STRINGS && coder == LATIN1) {
for (int j = (n-1) >> 1; j >= 0; j--) {
@@ -1573,11 +1597,11 @@
* @param coder the coder of dst[]
*/
void getBytes(byte dst[], int dstBegin, byte coder) {
if (this.coder == coder) {
System.arraycopy(value, 0, dst, dstBegin << coder, count << coder);
- } else { // this.coder == LATIN && coder == UTF16
+ } else { // this.coder == LATIN1 && coder == UTF16
StringLatin1.inflateSB(value, dst, dstBegin, count);
}
}
/* for readObject() */
< prev index next >