JavaSE StringBuffer的append()和构造器特别注意事项
@Test public void testNull() { String str = null; StringBuffer sb = new StringBuffer(); sb.append(str);//把str当成"null"这个字符串给放到sb里面去了 System.out.println(sb.length());//4 sb因为放入了null这个字符串,所以长度变成了4 System.out.println(sb);//null StringBuffer sb1=new StringBuffer(str);//抛异常,因为StringBuffer构造器会调用str.length(),但是str是个空的,就会抛异常 System.out.println(sb1);//不执行 }
上述代码多数人很容易搞错,尤其是在sout(sb.length());误认为输出的结果是0,但是结果是4
原因可以看源码知晓:
private AbstractStringBuilder appendNull() { ensureCapacityInternal(count + 4); int count = this.count; byte[] val = this.value; if (isLatin1()) { val[count++] = 'n'; val[count++] = 'u'; val[count++] = 'l'; val[count++] = 'l'; } else { count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l'); } this.count = count; return this; }
StringBuffer是AbstractStringBuilder的子类,StringBuffer的append()方法继承于AbstractStringBuilder,而AbstractStringBuilder中有一个针对添加空指针的appendNull()
的方法,这个方法的源码强调当这个指针是空的时候,则设立一个长度为4的byte[](当中存储null这个字符串),所以当我们在输出StringBuffer对象添加空指针之后的长度,这个长度就变成了4,内容为null ---> 这也就解释了为什么接下来的sout(sb)出的结果是null
第二个容易错的点就是:
StringBuffer sb1=new StringBuffer(str);
这个地方为什么会报错呢?还是需要看源码:
查看StringBuffer的构造器:
@HotSpotIntrinsicCandidate public StringBuffer(String str) { super(str); }
发现这个构造器继承了AbstractStringBuilder的构造方法,我们点开super(str)看一看:
AbstractStringBuilder(String str) { int length = str.length(); int capacity = (length < Integer.MAX_VALUE - 16) ? length + 16 : Integer.MAX_VALUE; final byte initCoder = str.coder(); coder = initCoder; value = (initCoder == LATIN1) ? new byte[capacity] : StringUTF16.newBytesFor(capacity); append(str); }
原因很明显:第一行str就可以看到,str调用了length(),直接会报NullPointerException空指针异常。
public NullPointerException() { super(); }