• 从源码了解String,StringBuffer和StringBuilder


    面试题:String,StringBuilder和StringBuffer的区别?

    String是不可变类,StringBuffer和StringBuilder是可变类;String在多次字符串拼接时效率低,且线程不安全,StringBuilder效率最高,但是线程不安全,StringBuffer效率在前两者其中,且是线程安全。

    源码分析:

    1.String

    (1)类定义

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


    String类是个final类,实现了Serializable(序列化接口),Comparable(比较大小接口)和CharSequence(只读字符序列接口)。String和其他八个基本数据类型的包装类共同为不可变类。

    (2)主要变量

    private final char value[];


    String类的底层基本是char类型数组,String的一些基本方法也是调用char数组的基本方法。

    (3)主要构造方法

    public String() {
      this.value = "".value;
    }


    String的默认值为"";

    (4)String常量池

    jvm在启动时就会加载的一块空间,符串常量池的特点就是有且只有一份相同的字面量,如果有其它相同的字面量,jvm则返回这个字面量的引用,如果没有相同的字面量,则在字符串常量池创建这个字面量并返回它的引用。通过使用new关键字获取的对象会放在堆里,而不会加载到字符串常量池,intern()方法能使一个位于堆中的字符串在运行期间动态地加入到字符串常量池中。

    (5)字符串拼接

    String字符串拼接一般通过用+号实现,正常情况下有两种形式:

    String a = "ab" + "cd";


    此时在JVM在编译时就认为这个加号是没有用处的,编译的时候就直接变成abcd,即使是后面添加多个字符串效率不会比StringBuiler或者StringBuffer慢。

    String a = "ab";
    String b = "cd";
    String c = a + b;


    此时字符串拼接系统会优化成通过new StringBuiler,进行两次append操作,该操作是在堆中进行,如果是进行多次拼接,会产生多个StringBuiler对象,效率自然会降低,但是如果是在同一行代码里做拼接操作,只是额外new了一个StringBuiler对象,效率也不会慢。

    2.StringBuilder

    (1)类定义

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


    StringBuilder类是final类,实现了Serializable(序列化接口),CharSequence(只读字符序列接口),其父类实现了CharSequence(只读字符序列接口)和Appendable(拼接接口),该类是可变类。

    (2)主要变量

    private final char value[];



    StringBuilder的底层基本实现和String是一致的

    (3)主要构造方法

    public StringBuilder() {
      super(16);
    }
    
    AbstractStringBuilder(int capacity) {
      value = new char[capacity];
    }


    StringBuiler类的基本构造方法是一个容量为16的字符串数组

    (4)字符串拼接

    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;
    }
    
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
              value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

     


    内部的实现是通过char数组操作的,如果超过容量,会发生通过数组拷贝方式的扩容操作。

    (5)线程安全性

      从上面的源码解析,count += len;并非原子操作,如果两个线程同时访问到这个方法,那么AbstractStringBuilder中的count是不是就是相同的,所以这两个线程都是在底层char数组的count位置开始append添加,那么最终的结果肯定就是在后执行的那个线程append进去的数据会将前面一个覆盖掉,所以StringBuilder在字符串拼接操作是线程不安全的。由于String的拼接也是通过StringBuiler来实现,所以String的字符拼接也不是线程安全的

    3.StringBuffer

    (1)类定义

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

    StringBuffer其父类实现了Serializable(序列化接口),CharSequence(只读字符序列接口),与StringBuilder有公共的父类AbstractStringBuilder,该类是可变类。

    (2)主要变量
    StringBuffer的底层基本实现和StringBuilder是一致的。

    (3)构造方法

    StringBuffer的构造方法和StringBuilder是一致的。

    (4)字符串拼接

    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

    StringBuffer字符串拼接基本与StringBuilder内部实现是一致的,主要是区别是在方法体上通过synchronized关键字加锁。

    (5)线程安全性

      从上面的源码解析,由于在方法加上synchronize关键字,所以字符串拼接操作是线程安全。

  • 相关阅读:
    定了!这场9月网易必看大会重磅来袭,报名通道正式开启!
    走向现代化数据分析架构:趋势与挑战
    Acrobat无法在本页面上执行文本识别
    解决QTTabBar2048无法卸载或者安装问题
    ArcPy获取要素类的别名
    ArcGIS Pro 安装语言包报指定路径为空
    使用MxDraw52后台操作dwg文件
    DevExpress列表取消右键折叠展开菜单
    QT界面开发入门7 — 菜单栏没有转到槽
    IO,NIO和AIO是Java网络编程的三种模型
  • 原文地址:https://www.cnblogs.com/hxlr/p/11417615.html
Copyright © 2020-2023  润新知