2019-08-20

浅谈String、StringBuffer 、StringBuilder和StringJoiner

可变性

String 类中使用 final 关键字修饰字符数组来保存字符串,private final char value[],所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中使用字符数组保存字符串char[] value, 没有用 final 关键字修饰,所以这两种对象都是可变的。

安全性

String 中的对象是不可变的,线程安全。
StringBuffer 对方法加了同步锁或者对调用的方法加 了同步锁,所以是线程安全的。
下面是StringBuffer 源码中的部分代码:

    @Override
    public synchronized int length() {
        return count;
    }

    @Override
    public synchronized int capacity() {
        return value.length;
    }

    @Override
    public synchronized void ensureCapacity(int minimumCapacity) {
        super.ensureCapacity(minimumCapacity);
    }

StringBuilder 可变,但是没有对方法加同步锁,所以是非线程安全的。

性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 与StringBuilder 每次都是对对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 能获得 10%~15% 左右的性能提升,但却有多线程不安全的风险。

对于三者使用的总结

操作少量的数据: 适用String
单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder
多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer

AbstractStringBuilder 扩容机制

由于StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,所以就来简单的探讨一下StringBuilder的扩容机制,StringBuffer 只需在此基础上加上同步锁就是。
下面我们在源码中分析:

public StringBuilder() {
        super(16);
    }
public StringBuilder(int capacity) {
        super(capacity);
    }
public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
 public StringBuilder(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }

从上面StringBuilder的构造方法可以看出默认容量为16,可以传入参数(CharSequence为可读可写序列,意思还可以传一个StringBuilder等的变量)。

   /*
     AbstractStringBuilder 中成员变量
   */
    char[] value;//StringBuilder本质就是可变长度的字符数组
    int count;//已有内容的长度
/*
这个方法保证minimumCapacity > 0
*/
 public void ensureCapacity(int minimumCapacity) {
        if (minimumCapacity > 0)
            ensureCapacityInternal(minimumCapacity);
    }

/*
这个方法就是获得一个长度较大的字符数组
*/
  private void ensureCapacityInternal(int minimumCapacity) {
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

/*
这个方法就是获取value新的值max(value.length*2+2,minimumCapacity)
*/
 private int newCapacity(int minCapacity) {
        int newCapacity = (value.length << 1) + 2;//左移一位,扩大两倍
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }


/*
获取容量的最大值,防止内存溢出
*/
private int hugeCapacity(int minCapacity) {
        if (Integer.MAX_VALUE - minCapacity < 0) { // 内存溢出
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

对于大数据的2进制运算,位移运算符比那些普通运算符的运算要快很多,因为程序仅仅移动一下而已,不去计算,这样提高了效率,节省了资源

这里简单说说StringJoiner

StringJoiner(JDK1.8),在源码中可以看到,内部其实运用的是StringBuilder ,感觉就是在StringBuilder 的基础上可以快速拼接字符串。

public final class StringJoiner {
    private final String prefix;//开头使用的字符序列 
    private final String delimiter;//要添加到每个元素之间的间隔符
    private final String suffix;// 最后使用的字符序列
    private StringBuilder value;//内部运用StringBuilder 
}
/*
添加内容是调用StringBuilder的append()添加方法
*/
public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
    }
/*
返回一个StringBuilder的值
*/
 private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);//若为null就new StringBuilder()
        }
        return value;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容

  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,373评论 0 4
  • 《Java从小白到大牛》纸质版已经上架了!!! 由字符组成的一串字符序列,称为“字符串”,在前面的章节中也多次用到...
    tony关东升阅读 808评论 0 2
  • 从网上复制的,看别人的比较全面,自己搬过来,方便以后查找。原链接:https://www.cnblogs.com/...
    lxtyp阅读 1,345评论 0 9
  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 829评论 1 6
  • 面向对象的三个特征 封装,继承,多态.这个应该是人人皆知.有时候也会加上抽象. 多态的好处 允许不同类对象对同一消...
    Blizzard_liu阅读 1,312评论 0 6