Java字符串 -- String

字符串的不可变性

定义一个字符串

String s = "abcd";

使用变量赋值

String s2 = s;

字符串连接

s = s.contact("ef");

可以看出,String对象一旦被创建出来,就无法修改。如果需要一个可修改的字符串,应该使用StringBuffer或者StringBuilder,否则会有大量时间浪费在垃圾回收上。

编译器对“+”的优化

  • 对于String s = "a" + "b",编译后变成String s = "ab"。
  • 对于String s = "a" + 变量,编译后用StringBuilder.append()方法替代,最后调用toString()方法。

字符串拼接的几种方式

  • 使用“+”拼接
String str = "str";
str += String.valueOf(i);

使用“+”拼接,实际上是用StringBuilder.append()。

  • String.concat()
String str = "str";
str = str.concat(String.valueOf(i));

String.contact实现的原理是,创建一个字符数组,长度是已有字符串和待拼接字符串的长度之和,再把两个字符串的值复制到新的字符数组中,并使用这个字符数组创建一个新的String对象并返回。简单地说就是new了一个新的String对象。

  • StringBuilder.append()
StringBuilder builder = new StringBuilder("str");
builder.append(String.valueOf(i));

StringBuilder.append实现的原理是,StringBuilder内部也有一个char数组,但不是final的,进行append时,会直接拷贝字符到内部的字符数组中,如果字符数组长度不够,会进行扩展。

  • StringBuffer.append()
StringBuffer buffer = new StringBuffer("str");
buffer.append(String.valueOf(i));

StringBuffer.append和StringBuilder.append原理是一样的,不同的是,StringBuffer的append方法是用synchronized修饰的,是线程安全的。

  • String.join()
String str = "str";
str = String.join("", str, String.valueOf(i));

String.join内部也是用StringBuilder来实现的。

字符串拼接性能大比拼

测试代码都类似下面这段:

public void stringJoint1() {
    long t1 = System.currentTimeMillis();
    String str = "str";
    for (int i = 0; i < 50000; i ++) {
        str += String.valueOf(i);
    }
    long t2 = System.currentTimeMillis();
    System.out.println("+ cost: " + (t2 - t1));
}

运行结果:

String.concat cost: 1902
StringBuilder cost: 6
StringBuffer cost: 5
+ cost: 5202
String.join cost: 5298

多次运行之后,可以观察到大概的运行效率是:
StringBuilder ≈ StringBuffer < String.contact < String.join ≈ "+"

  • StringBuffer相对StringBuilder多了同步的操作,所以在单线程环境下运行效率差不多;
  • String.contact每次都会创建新的字符串,所以会更慢一些;
  • String.join和“+”每次都会创建StringBuilder对象所以更慢。

总结一下:

  • 如果不在循环体中拼接字符串,直接使用+就可以。
  • 如果在循环体中拼接字符串,非并发时使用StringBuilder,并发时使用StringBuffer。

你可能感兴趣的:(Java字符串 -- String)