先看一下String的源码:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    
 
    private final char value[];
 
     private int hash; // Default to 0
 
    
    private static final long serialVersionUID = -6849794470754667710L;
    
    ......此处省略N多代码
    
    /**
     * Initializes a newly created {@code String} object so that it represents
     * the same sequence of characters as the argument; in other words, the
     * newly created string is a copy of the argument string. Unless an
     * explicit copy of {@code original} is needed, use of this constructor is
     * unnecessary since Strings are immutable.
     *
     * @param  original
     *         A {@code String}
     */
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
 
}

在上面 贴出了String的源代码,我们可以看到,String类是final修饰的,然后还有个成员属性 value  它也是final的并且是一个char类型的数组

通过构造方法可以看到,我们传递的参数值 是直接赋值给了 value 

那么我们说明 String它是一个不可变字符串,底层是一个char类型的数组

实际上我们经常 这样写 String  a = "abc"; 这个时候 声明的变量值是在常量池中的。

到此,有的同学可能要说了,String里面我们不是可以使用 + 连接符 来进行String的拼接吗。

的确如此,我们是可以使用 "+" 来拼接字符串,不过 这里 jdk的虚拟机是做了优化的,并不是表面看到的使用 连接符 对原来的String做了拼接,那么我们来看下 它是如何编译的。

有如下代码:

public class Test{
	public static void main(String [] args){
			String str = "abc";
			String str1= "def";
			str = str+str1;
			System.out.println(str);
	}
}

我们在控制台 中 通过 javac 编译,然后通过java执行 看到结果是

结果都知道是 "abcdef" 那么这个地方的str到底是否被改变,我们可以看编译后的class字节码文件

Android 字符串拼色 字符串拼接底层原理_java

 

我们通过 javap -c Test 来观察,结果如下图

Android 字符串拼色 字符串拼接底层原理_Android 字符串拼色_02

 

我们看到Code 的 第 0 和 第 3 标识处,是我们声明的变量值  "abc" 和 "def"

再往下走,我们在java中的代码是使用了 "+" 连接符号的,此处看到 Code 第  6 处 new StringBuilder  

再往下走,看到 Code 的第 14 和 第 18 ,使用了StringBuilder的 append(),那么我们可以得出一个结论,我们在使用String的时候,使用连接符,并不是表面看到的是直接操作原来的变量做值的拼接,而是使用的StringBuilder对象,追加的内容,

最后 在 Code的21处,有一个 toString()方法,是把当前StringBuilder的对象变成了String。

好了,到此,我们剖析String源码到此结束。

结论就是 String底层是一个不可变字符串,使用连接符的时候,实际上是经过了StringBuilder的优化处理的。并不是在原来的String对象中做追加