StringBuffer的append 源码解析
前言
因为有面试官问到,StringBuffer是怎么实现append的;
简述一下思路就行
那么想到的肯定是动态数组哇,但是我想的是,不用每次都new 一个数组;
不用频繁的移动字符串数组。
基本描述是ok的~但是看看源码没毛病
dkdk 加油加油
debug的过程还是蛮有趣的
文章来自本人的面试经历:blog.csdn.net/pmdream/art…参加挑战可以文章来自别的博客的原创文章~所以来进行今日份打卡
源码
append
@Override public synchronized StringBuffer append(Object obj) { toStringCache = null; super.append(String.valueOf(obj)); return this; } @Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } /** * Appends the specified {@code StringBuffer} to this sequence. * <p> * The characters of the {@code StringBuffer} argument are appended, * in order, to the contents of this {@code StringBuffer}, increasing the * length of this {@code StringBuffer} by the length of the argument. * If {@code sb} is {@code null}, then the four characters * {@code "null"} are appended to this {@code StringBuffer}. * <p> * Let <i>n</i> be the length of the old character sequence, the one * contained in the {@code StringBuffer} just prior to execution of the * {@code append} method. Then the character at index <i>k</i> in * the new character sequence is equal to the character at index <i>k</i> * in the old character sequence, if <i>k</i> is less than <i>n</i>; * otherwise, it is equal to the character at index <i>k-n</i> in the * argument {@code sb}. * <p> * This method synchronizes on {@code this}, the destination * object, but does not synchronize on the source ({@code sb}). * * @param sb the {@code StringBuffer} to append. * @return a reference to this object. * @since 1.4 */ public synchronized StringBuffer append(StringBuffer sb) { toStringCache = null; super.append(sb); return this; } /** * @since 1.8 */ @Override synchronized StringBuffer append(AbstractStringBuilder asb) { toStringCache = null; super.append(asb); return this; } /** * Appends the specified {@code CharSequence} to this * sequence. * <p> * The characters of the {@code CharSequence} argument are appended, * in order, increasing the length of this sequence by the length of the * argument. * * <p>The result of this method is exactly the same as if it were an * invocation of this.append(s, 0, s.length()); * * <p>This method synchronizes on {@code this}, the destination * object, but does not synchronize on the source ({@code s}). * * <p>If {@code s} is {@code null}, then the four characters * {@code "null"} are appended. * * @param s the {@code CharSequence} to append. * @return a reference to this object. * @since 1.5 */ @Override public synchronized StringBuffer append(CharSequence s) { toStringCache = null; super.append(s); return this; } /** * @throws IndexOutOfBoundsException {@inheritDoc} * @since 1.5 */ @Override public synchronized StringBuffer append(CharSequence s, int start, int end) { toStringCache = null; super.append(s, start, end); return this; } @Override public synchronized StringBuffer append(char[] str) { toStringCache = null; super.append(str); return this; } /** * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override public synchronized StringBuffer append(char[] str, int offset, int len) { toStringCache = null; super.append(str, offset, len); return this; } @Override public synchronized StringBuffer append(boolean b) { toStringCache = null; super.append(b); return this; } @Override public synchronized StringBuffer append(char c) { toStringCache = null; super.append(c); return this; } @Override public synchronized StringBuffer append(int i) { toStringCache = null; super.append(i); return this; }复制代码
不管是append什么东西,
最后都是super.append(obj);
注意都是synchronized修饰的线程安全
toStringCache
Cleared whenever the StringBuffer is modified.那我如果调用append,这个东西就会被清空,相当于上次调用toString的一个cache;
/** * A cache of the last value returned by toString. Cleared * whenever the StringBuffer is modified. */ private transient char[] toStringCache;复制代码
// 这样写是ok的,StringBuffer是可以接受 字符串 也可以接受数字等等
public static void main(String[] args) { StringBuffer sb = new StringBuffer(); sb.append(1); System.out.println(sb.toString()); sb.append("c"); System.out.println(sb.toString()); }复制代码
append数字的源码
/** * Appends the string representation of the {@code int} * argument to this sequence. * <p> * The overall effect is exactly as if the argument were converted * to a string by the method {@link String#valueOf(int)}, * and the characters of that string were then * {@link #append(String) appended} to this character sequence. * * @param i an {@code int}. * @return a reference to this object. */ public AbstractStringBuilder append(int i) { if (i == Integer.MIN_VALUE) { append("-2147483648"); return this; } int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1 : Integer.stringSize(i); int spaceNeeded = count + appendedLength; ensureCapacityInternal(spaceNeeded); Integer.getChars(i, spaceNeeded, value); count = spaceNeeded; return this; }复制代码
append 字符串的源码
/** * Appends the specified string to this character sequence. * <p> * The characters of the {@code String} argument are appended, in * order, increasing the length of this sequence by the length of the * argument. If {@code str} is {@code null}, then the four * characters {@code "null"} are appended. * <p> * Let <i>n</i> be the length of this character sequence just prior to * execution of the {@code append} method. Then the character at * index <i>k</i> in the new character sequence is equal to the character * at index <i>k</i> in the old character sequence, if <i>k</i> is less * than <i>n</i>; otherwise, it is equal to the character at index * <i>k-n</i> in the argument {@code str}. * * @param str a string. * @return a reference to this object. */ public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; }复制代码
对比上面两个代码, 主要是ensureCapacityInternal 还有getchars
ensureCapacityInternal
传进来的长度其实是,后面新增的字符串的长度
/** * For positive values of {@code minimumCapacity}, this method * behaves like {@code ensureCapacity}, however it is never * synchronized. * If {@code minimumCapacity} is non positive due to numeric * overflow, this method throws {@code OutOfMemoryError}. */ private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } }复制代码
// 就是把老数组,弄到新数组上面去,用新的长度,将长度扩大成传入的参数长度,并重新赋值给value
public static char[] copyOf(char[] original, int newLength) { char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }复制代码
扩容的新的容量计算函数newCapacity
/** * Returns a capacity at least as large as the given minimum capacity. * Returns the current capacity increased by the same amount + 2 if * that suffices. * Will not return a capacity greater than {@code MAX_ARRAY_SIZE} * unless the given minimum capacity is greater than that. * * @param minCapacity the desired minimum capacity * @throws OutOfMemoryError if minCapacity is less than zero or * greater than Integer.MAX_VALUE */ private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }复制代码
这个是怎么算的?
value.length 初始因为字符串是hello,分配了16个字符长度。
x<<1 相当于 x中存储的整数左移1位(相当于乘以2)
所以(16 << 1) +2 = 34
这边 相当于,int newCapacity = (value.length << 1) + 2 与minCapacity谁大谁当新的容量
debug过程
原字符串hello,要追加world
可以看到是有cache的
这个长度是合起来的长度,最小的长度
可以看到,其实初始化hello的时候,value 默认分配是16,其实是有一定富裕的,所以如果10 -16 没有>0 ,那么不需要扩容 ;
getChars 就是传入,原始字符串的开始和结束,然后还有扩充完的字符数组(也许不用扩充),然后新的要从哪里开始
本次执行的value是world:后面执行字符串拷贝就行了
加上当前的值,那么这个字符串的长度变成了10
作者:攻城新一
链接:https://juejin.cn/post/7015417663853690893