String是final类, 而且其方法都被final修饰数组
String经过char数组来保存字符串app
对String对象的任何操做都不会影响到原来的String对象, 全部的改变都会建立新String对象ui
?--- 常量赋值3d
代码:指针
内存图:对象
分析:对于常量赋值来讲, 变量s1始终指向了字符串常量池的字符串(只有一份)blog
?--- new String("xxx");的运行
内存
代码:字符串
源代码:编译
内存图:
分析:
首先先来考虑一下这一句的执行过程,这句一共生成了两个对象,分别是“abc” 和 new String("abc"),考虑类的加载对一个类只会执行一次,“abc”在类加载的时就已经建立驻留(若是该类加载以前已经有"abc"字符串驻留了,那么不须要重复建立用于驻留的"abc"实例)。驻留的字符串是放在全局共享的字符串常量池中的。
在这段代码后续被运行的时候,"abc"字面量对应的String实例已经固定了,不会再被重复建立。因此这段代码将常量池中的对象复制一份放到heap中,而且把heap中的这个对象的引用交给s1 持有。因此能够看到“abc” 是存在于常量池中 ,而s1指向堆里的对象。
?---常量字符串的拼接(使用+)
代码:
内存图:
分析:
当一个字符串由多个字符串常量链接而成时,它本身确定也是字符串常量, 该字符串是在编译期就能肯定。先是在池里生成“a”和“b”,再经过拼接的方式生成"ab"
若一个String对象被final修饰, 而且形式为final String s = "xxx";能够将之看作是常量
?---很是量字符串拼接(使用+)
代码:
内存图:
分析:
这句话一共生成了5个对象,首先会先在池子生成“a”和“b”,而后会在堆里生成对象new String("a") 和 new String("b),这两个对象分别指向常量池的所对应的字符串,接着因为“+”的做用下,建立了新的对象,这个对象经过利用以前的对象所指向的字符进行拼接生成“ab”,即这波操做是在堆里实现的,不会将生成的"ab"放在常量池里,此时以前的两个对象已经没有做用了,须要等待垃圾回收。
?---小结
无论是new String("XXX")和直接常量赋值, 都会在字符串常量池建立.只是new String("XXX")方式会在堆中建立一个中转站去指向常量池的对象, 而常量赋值的变量直接赋值给变量
当使用了变量字符串的拼接(+, sb.append)都只会在堆区建立该字符串对象, 并不会在常量池建立新生成的字符串
用法解释:
当调用intern方法时,若是池已经包含与equals(Object)方法肯定的至关于此String对象的字符串,则返回来自池的字符串。 不然,此String对象将添加到池中,并返回对此String对象的引用
举个栗子
代码:
内存图:
分析:
能够看出,是先在池里建立“a”好后,返回一个对象引用赋给堆里的对象new String("a"),也就s1所指向的地方,在堆里。经过调用 intern() 方法,在池里找到S1对象所对应的字符串,而且进行返回给S2对象,因此S2所指向的地方,在常量池里。
举个栗子
代码:
内存图:
分析:因为常量池不存在ba, 因此返回堆区ba的地址并添加到常量池中, s2指向了常量池的inte指针
若+号先后为常量,编译期会处理
若+号先后存在着变量,首先以最左边的字符串为参数建立StringBuilder对象,而后依次对右边进行append操做,最后将StringBuilder对象经过toString()方法转换成String对象