1.加号+拼接
这个用法是最初学习当中最常用的方法。原来也一直在用。
后来有了代码规范,在log打印日志的地方,让使用模板形式的字符串拼接。
才因此引发的思考。
这种+连接的优缺点在哪。
优点:只是方便
缺点:String是一个不可变的类,这导致
有的人说:a+b+c 本质上是 new String + new String + new String 。。。。这使得过量创建对象。极限状态下,gc的速度赶不上new的速度,就oom了。
也有的人说:String直接相加已经都被编译器优化成StringBuilder了,只是循环里优化的不太合理。所以,String相加快还是StringBuilder快,其实只是StringBuilder调用方式对比。。。
这两个说法看起来应该似乎跟编译版本有关系,具体的还不了解。
支路:所以String不可变的意义是?
1.方便做hash中的key
因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
2.String pool的需要
如果String被创建了,从String pool中直接获取引用,只要String 不改变,才能从String pool获取
3.安全性
String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。
4.线程安全
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
2.String.format
可读性非常好
效率:低于stringbuilder
String.format具有更大的重量,String.format首先使用正则表达式解析输入,然后填充参数。因为它创建了一个新的Formatter,解析了您的输入格式字符串,创建了一个StringBuilder,将所有内容附加到它并调用toString()。所以性能最差。
3.String.concat
性能棒
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); } |
---|
参数不可以是null,他没给使用者提供自动检测null的功能,会报npe
简单粗暴,直接Arrays.copyOf,直接内存复制,这根StringBuilder原理类似,但是它不用初始化StringBuilder对象,只是每次concat都会创建一个新的String对象,所以在有些情况下它比StringBuilder要快一点。
支路:Arrays.copyOf是什么?
是创建一个新的数组(也就是分配了一个新的内存空间),然后调用System.arraycopy()复制内容,赋值给新数组,然后返回新数组。
浅拷贝:增加一个指针,指向了原来已经存在的对象地址,gc之后容易给它误回收了。
深拷贝:将原对象完完整整copy出一份新对象,并指向他。之后跟原对象毫无关系。
4.StringBuilder
这是咱们推荐的String处理工具,效率综合最好。
但他的可读性。。。
支路:StringBuilder的原理?
String源码:private final char value[];
StringBuilder源码:
1.StringBuilder extends AbstractStringBuilder
他继承AbstractStringBuilder
2. char[] value;
他定义了一个char[],默认长度16,非final,非static。
3.ensureCapacityInternal()
private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } |
---|
每次修改,先调用扩容函数
长度要不够用,就申请一个更大的空间,然后将原来的内容,浅拷贝给那片新的空间
4.getchars()
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { if (srcBegin < 0) throw new StringIndexOutOfBoundsException(srcBegin); if ((srcEnd < 0) || (srcEnd > count)) throw new StringIndexOutOfBoundsException(srcEnd); if (srcBegin > srcEnd) throw new StringIndexOutOfBoundsException("srcBegin > srcEnd"); System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } |
---|
修改String的最终方法,先判断是否空指针,再调用系统的System.arraycopy,上面的浅拷贝,本质也是调用的系统native方法。
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); |
---|
5.StringBuffer
它和StringBuilder是同门兄弟,都继承与AbstractStringBuilder
咱们代码规范表示,除非的多线程,单线程禁用。
他如何实现的线程安全?
他使用了Synchronized锁住待编辑的String,与stringbuilder相比有额外负担的。
奇淫技巧:Idea->Settings->Editor->intentions->StringBuilder,当使用+连接时提示改用stringbuilder
注:以上内容都是我编的
参考文献:
1.String使用final修饰的好处:在java中为什么String是被final的_牛顿爱吃水果的博客-CSDN博客_java string为什么是final
2.java String、String.concat和StringBuilder性能对比:java String、String.concat和StringBuilder性能对比 - 走看看
3.String+,StringBuilder,String.format运行效率比较:String+,StringBuilder,String.format运行效率比较_锦聪的博客-CSDN博客_string.format效率