这个知识点几乎是面试中的必考题,其重要程度丝毫不亚于,ArrayList,LinkedList之间的区别这一类知识点,下面来总结一下。
String
String在Java中是不可变对象,无论是substring, concat还是replace操作,还是我们平常开发中经常使用到的字符串拼接。都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。
对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象。
以上图片来自https://blog.csdn.net/weixin_41101173/article/details/79677982
可以看出若是对字符串进行拼接操作,内存中会重新开辟一块内存空间。
StringBuilder
频繁的对字符串操作需要频繁的开辟内存空间,对性能产生不利影响,甚至还有可能产生内存泄露,那么StringBuilder便可以很好的解决这个问题
图片来自https://blog.csdn.net/csxypr/article/details/92378336
可以看出StringBuilder对字符串操作是在原有字符串对象上进行操作的,而不会重新开辟内存空间。所以在对字符串做拼接操作时,推荐使用StringBuilder,当然仅限于单线程环境下,那么多线程环境下应该怎么做呢。
StringBuffer
在单线程环境下使用StringBuilder对字符串进行操作,由于StringBuilder是非线程安全的,所以StringBuffer其实在使用方法上和StringBuilder并没有本质差别,只不过在核心方法上加了synchronized关键字以确保线程安全,可查看源码。
@Override
public synchronized int length() {
return count;
}
@Override
public synchronized int capacity() {
return value.length;
}
@Override
public synchronized void ensureCapacity(int minimumCapacity) {
super.ensureCapacity(minimumCapacity);
}
/**
* @since 1.5
*/
@Override
public synchronized void trimToSize() {
super.trimToSize();
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
@Override
public synchronized void setLength(int newLength) {
toStringCache = null;
super.setLength(newLength);
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
@Override
public synchronized char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
/**
* @since 1.5
*/
@Override
public synchronized int codePointAt(int index) {
return super.codePointAt(index);
}
/**
* @since 1.5
*/
@Override
public synchronized int codePointBefore(int index) {
return super.codePointBefore(index);
}
/**
* @since 1.5
*/
@Override
public synchronized int codePointCount(int beginIndex, int endIndex) {
return super.codePointCount(beginIndex, endIndex);
}