zoukankan      html  css  js  c++  java
  • Java基础08 String、StringBuilder、StringBuffer的区别

    String 类

      在Java的编程中,字符串是运用的比较多的类型,字符串是由Java的String类来创建的,需要注意的是String类被 final 修饰的类,这意味着该类不能继承,该类的对象值是不可变的。

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
    

      但在平时使用的时候,我们经常这样操作来改变String对象变量的值

    String str = "hello";
    str += "world"; 
    

      其实这样的操作很消耗内存,浪费存储空间,我们来看下上面的语句块会产生哪些操作。
    String

    1. 在堆上开辟一个空间用于存储 hello
    2. 在栈上分配一个空间用于存储str,存储的值是堆内存的 hello 地址
    3. 在堆上开辟一个空间用于存储 world.
    4. 拼接 hello 与 world.两个字符串,放入堆另外开辟的一个内存空间
    5. 栈上存储str的值变为 helloworld. 的堆内存地址

      经过上面的步骤分析,我们可以知道,String 类型的字符串在进行拼接的时候,在堆内存上开辟了三次空间,而且只使用其中一个内存空间,这无疑是对堆内存空间的极大的浪费。

      为了能解决这个问题,也就引入了 StringBuild 和 StringBuffer。

    StringBuffer与StringBuilder

      StringBuilder 与 StringBuffer 两个类主要用于对字符串频繁修改的场景,它们是对 String 的优化,在追加字符串的时候不会去堆上开辟新的空间,会直接在已有的堆空间追加。
    String相关结构层次

      上图是String、StringBuffer、StringBuilder的层级关系图,我们可以看出StringBuilder与StringBuffer继承了AbstractStringBuilder抽象类,查看源码可知,StringBuilder与StringBuffer最终使用的方法还是它们的父类AbstractStringBuilder中的方法,唯一不同的是StringBuffer比StringBuilder多做了一个加锁的操作,这也就导致StringBuffer是线程安全的,但执行效率比较低,而StringBuilder不是线程安全的,但执行效率较高。

    StringBuilder

    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);	// 调用本类的
    }
    
    @Override
    public StringBuilder append(String str) {	// 没有加锁
        super.append(str);	// 直接调用父类的追加方法
        return this;
    }
    
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    

    StringBuffer

    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);	// 调用本类的
    }
    
    @Override
    public synchronized StringBuffer append(String str) {	// 加锁
        toStringCache = null;
        super.append(str);	// 调用父类的追加方法
        return this;
    }
    
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    

      可能有些疑问,为什么String、StringBuilder、StringBuffer三个类都是被 final 修饰,但只有String的值是不可变的呢?
      其实很简单,StringBuilder、StringBuffer确实是被 final 修饰的,而且他们本身也确实是不可变的,但我们需要注意的一点,他们追加的真正操作是在它们的父类中进行的,而它们的父类是没有被 final 修饰,这也就间接的理解StringBuilder、StringBuffer是可变的字符串,追加的时候不需要在堆内存开辟新的空间。

    public final class StringBuilder
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    {
    

    总结:三者的区别

    1. 三者都是被 final 修饰的类,但String类是不可变的,而其它两个可以间接理解为可变的。
    2. StringBuilder和String不是线程安全的,StringBuffer是线程安全的。
    3. 效率:StringBuilder > StringBuffer。
    4. 在字符串变量的值不经常改变的情况下(甚至不变),可以使用String,也可以使用StringBuilder;在字符串变量的值经常改变且不是多线程环境下,使用StringBuilder;在字符串变量的值经常改变且在多线程环境下,使用StringBuffer.
  • 相关阅读:
    16、cgminer学习之:popen函数和system函数详解(执行系统命令)
    16、cgminer学习之:pthread_mutex_init和pthread_cond_init
    15、python学习手册之:元组、文件及其他
    15、python学习手册之:列表和字典
    Chorme浏览器中使用flash debug版本
    Best Practices
    Titled-Contributing to Tiled
    Titled
    VS2010配合SVN搭建使用
    Google code问题记录
  • 原文地址:https://www.cnblogs.com/sophia-show/p/13646885.html
Copyright © 2011-2022 走看看