Java9のStringABuilder.appndの処理
Java9の変更点を調べていたら、ソースコードが見たくなってきたので、openjdkのソースコードを見てみた。
Stringに関しては以下のブログで紹介されています。
今回調べて見たのでは、StringBuilder.appendの処理。
LATIN1からUTF-16を追加するときの処理です。
ソースコード
StringBuilder
public StringBuilder append(String str) { super.append(str); return this; }
AbstractStringBuilder
public AbstractStringBuilder append(String str) { if (str == null) { return appendNull(); } int len = str.length(); ensureCapacityInternal(count + len); putStringAt(count, str); count += len; return this; }
ensureCapacityInternalで領域を確保して、putStringAtで結合しているようです。
ensureCapacityInternalに関しては、どのようなオーバーフローを気にしているのか?newCapacityにはどのようなサイズを取得しようとしているのかが、正直良くわからなかったです。
private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code int oldCapacity = value.length >> coder; if (minimumCapacity - oldCapacity > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity) << coder); } }
private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = value.length >> coder; int newCapacity = (oldCapacity << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } int SAFE_BOUND = MAX_ARRAY_SIZE >> coder; return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }
そして本題はputStringAtです。
この中でcoderを比較して違っていたら拡張しています。
private final void putStringAt(int index, String str) { if (getCoder() != str.coder()) { inflate(); } str.getBytes(value, index, coder); }
ここで一文字ずつコピーしているのがわかります。
public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { // We need a range check here because 'putChar' has no checks checkBoundsOffCount(dstOff, len, dst); for (int i = 0; i < len; i++) { putChar(dst, dstOff++, src[srcOff++] & 0xff); } }
static void putChar(byte[] val, int index, int c) { assert index >= 0 && index < length(val) : "Trusted caller missed bounds check"; index <<= 1; val[index++] = (byte)(c >> HI_BYTE_SHIFT); val[index] = (byte)(c >> LO_BYTE_SHIFT); }
感想
綺麗なソースコードが読めて、学びはたくさんあるが、読むのは結構難しい。