美文网首页Java游戏编程
String,StringBuilder,StringBuffe

String,StringBuilder,StringBuffe

作者: 0爱上1 | 来源:发表于2018-05-24 12:19 被阅读1155次

    定义:

        从jdk1.5开始提供的新的封装字符串的类,StringBuilder,其字符串拼接操作的效率远远高于 String。

        Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串

    简介:

        我们知道字符串其实就是由若干个字符线性排列而成的,可以理解为字符数组Array,那么既然是数组实现的,那就需要考虑到数组的特性,数组在内存中是一块连续的地址空间块,即在定义数组的时候需要指定数组的大小

        换言之, 数组就分为可变数组和不可变数组。可变数组能够动态插入和删除,而不可变数组一旦分配好空间后则不能进行动态插入或删除操作。

        在实际的字符串应用场景中,涉及到多种操作,比如字符串的插入,删除,修改,拼接,查询,替换...

    String:

       不可变类,属性value为不可变数组,即String初始化构造器没有初始容量为16的概念,你定义多少,String中字符数组的长度就是多少,不存在字符数组扩容一说。看下源码:

    2 3

    final修饰的String 类,以及final修饰的char[] value,表示String类不可被继承,且value只能被初始化一次。这里的value变量其实就是存储了String字符串中的所有字符。

    那既然String,不可变。我们再看下它的截取方法subString()实现

    4

    这里可以看到,在substring方法中,如果传入的参数为0,就返回自身原对象,否则就是重新创建一个新的对象

    5 6

    类似的我们可以看到,String类的concat方法,replace方法,都是内部重新生成一个String对象的。

    这也就是为什么我们如果采用String对象频繁的进行拼接,截取,替换操作效率很低下的原因。

    下面再看下StringBuilder对象的源码,分析为何其在做字符串的拼接,截取,替换方面效率远远高于String

    StringBuilder:

        内部可变数组,存在初始化StringBuilder对象中字符数组容量为16,存在扩容

    7

    StringBuilder类继承AbstractStringBuilder抽象类,其中StringBuilder的大部分方法都是直接调用的父类的实现。

    首先看下StringBuilder的构造方法

    8

    1:空参数的构造方法

    9 10

    2:自定义初始容量-构造函数

    11

    3:以字符串String 作为参数的构造

    12

    在参数Str 数组长度的基础上再增加16个字符长度,作为StringBuilder实例的初始数组容量,并将str字符串 append到StringBuilder的数组中。

    13

    具体看下父类AbstractStringBuilder的append方法

    14

    1:首先判断append的参数是否为null,如果为null的话,这里也是可以append进去的

    15

    其中ensureCapacityInternal方法是确保这次append 的时候StringBuilder的内部数组容量是满足的,即这次要append的null字符长度为4,加上之前内部数组中已有的字符位数c之后作为参数执行。

    16

    2:如果不为null的话,就获取这次需要append的str的字符长度。紧接着执行是否需要扩容的方法

    3:重点看下append方法的关键:String的 getChars方法(从str的0位开始,到str的长度,当前StringBuilder对象的字符数组,当前数组已有的字符长度)

    17 18

    其实是调用了System的arraycopy方法 参数如下:

        value 为str的内部不可变字符数组,

        srcBegin 为从str 字符串数组的0下标开始,

        srcEnd 为str字符串数组的长度,

        dst 为StringBuilder对象的内部可变字符数组,

        dstBegin 则为StringBuilder对象中已有的字符长度(char[] 已有的元素长度)

    即整个StringBuilder的append方法,本质上是调用System的native方法,直接将String 类型的str字符串中的字符数组,拷贝到了StringBuilder的字符数组中

    19

    toString():

        最后说下StringBuilder的toString方法,

        这里的toString方法直接new 一个String对象,将StringBuilder对象的value进行一个拷贝,重新生成一个对象,不共享之前StringBuilder的char[]

    以上就是StringBuilder的拼接字符串的原理分析,可以发现没有像String一样去重新new 对象,所以在频繁的拼接字符上,StringBuilder的效率远远高于String类。

    StringBuffer:

        线程安全的高效字符串操作类,看下源码:

    19

    类图和StringBuilder一样,不多说

    构造函数:

    20

    和StringBuilder一样,也不用多说,重点看下其append方法:

    21

    可以看到这里就是在append方法上加了同步锁,来实现多线程下的线程安全。其他的和StringBuilder一致。

    这里比StringBuilder多了一个参数

    22

    这里的作用简单介绍一下,就是去缓存toString的

    可以看下StringBuffer的toString方法

    23

    这里的作用就是如果StringBuffer对象此时存在toStringCache,在多次调用其toString方法时,其new出来的String对象是会共享同一个char[] 内存的,达到共享的目的。但是StringBuffer只要做了修改,其toStringCache属性值都会置null处理。这也是StringBuffer和StringBuilder的一个区别点。

    总结:

        String 类不可变,内部维护的char[] 数组长度不可变,为final修饰,String类也是final修饰,不存在扩容。字符串拼接,截取,都会生成一个新的对象。频繁操作字符串效率低下,因为每次都会生成新的对象。

        StringBuilder 类内部维护可变长度char[] , 初始化数组容量为16,存在扩容, 其append拼接字符串方法内部调用System的native方法,进行数组的拷贝,不会重新生成新的StringBuilder对象。非线程安全的字符串操作类, 其每次调用 toString方法而重新生成的String对象,不会共享StringBuilder对象内部的char[],会进行一次char[]的copy操作。

        StringBuffer 类内部维护可变长度char[], 基本上与StringBuilder一致,但其为线程安全的字符串操作类,大部分方法都采用了Synchronized关键字修改,以此来实现在多线程下的操作字符串的安全性。其toString方法而重新生成的String对象,会共享StringBuffer对象中的toStringCache属性(char[]),但是每次的StringBuffer对象修改,都会置null该属性值。

    相关文章

      网友评论

        本文标题:String,StringBuilder,StringBuffe

        本文链接:https://www.haomeiwen.com/subject/dhnljftx.html