public class Concatenation { public static void main(String[] args) { String mango = "mango"; String s = "abc" + mango + "def" + 47; System.out.println(s); } } /* Output: abcmangodef47 *///:~
引入一段代码,大家都知道“+”与“+=”操作符是java中仅有的两个重载过的操作符(java并不允许程序员重载任何操作符),“+”可以用来连接String,如上述代码所示。
可能大家都知道这段代码是怎么工作的,按照编程思想书中的描述,可以用JDK自带的工具javap来反编译上述代码,命令如下:javap -c Concatenation 这里的“-c”表示将生成JVM代码。我跑了一下结果如下:
public class Concatenation { public Concatenation(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>": ()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String mango 2: astore_1 3: new #3 // class java/lang/StringBuilder 6: dup 7: invokespecial #4 // Method java/lang/StringBuilder."< init>":()V 10: ldc #5 // String abc 12: invokevirtual #6 // Method java/lang/StringBuilder.ap pend:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: aload_1 16: invokevirtual #6 // Method java/lang/StringBuilder.ap pend:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: ldc #7 // String def 21: invokevirtual #6 // Method java/lang/StringBuilder.ap pend:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: bipush 47 26: invokevirtual #8 // Method java/lang/StringBuilder.ap pend:(I)Ljava/lang/StringBuilder; 29: invokevirtual #9 // Method java/lang/StringBuilder.to String:()Ljava/lang/String; 32: astore_2 33: getstatic #10 // Field java/lang/System.out:Ljava/ io/PrintStream; 36: aload_2 37: invokevirtual #11 // Method java/io/PrintStream.printl n:(Ljava/lang/String;)V 40: return }
据说有汇编语言经验的看着会觉得眼熟,这里的重点就是编译器自动引入了java.lang.StringBuilder类,虽然源码并没有使用StringBuilder类,但是编译器自作主张地使用了它,因为它更高效。
StringBuilder是java SE5引入的,如果看源码会注意到这样一段注释
* @author Michael McCloskey * @see java.lang.StringBuffer * @see java.lang.String * @since 1.5 */ public final class StringBuilder
since 1.5,那么在这之前java用的是什么呢,就是StringBuffer。
* @author Arthur van Hoff * @see java.lang.StringBuilder * @see java.lang.String * @since JDK1.0 */ public final class StringBuffer
1.0就已经有了,而且是线程安全的,因此开销也会大些,所以在java SE5/6中(现在已经到8了),字符串的操作应该还会更快一些。
看过源码就会发现,注释的第一句话就对线程是否安全做了说明
/* * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.lang; import java.util.Arrays; /** * A thread-safe, mutable sequence of characters. * A string buffer is like a {@link String}, but can be modified. At any * point in time it contains some particular sequence of characters, but * the length and content of the sequence can be changed through certain * method calls.
看看源码就会发现,StringBuffer类的很多方法都是用了synchronized关键字声明,而StringBuilder并没有,StringBuilder属于非线程安全。
StringBuffer和StringBuilder的父类都是AbstractStringBuilder,他们的构造方法都是调用父类的构造方法
/** * Constructs a string buffer with no characters in it and an * initial capacity of 16 characters. */ public StringBuffer() { super(16); }
/** * Constructs a string builder with no characters in it and an * initial capacity of 16 characters. */ public StringBuilder() { super(16); }
/** * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { value = new char[capacity]; }