• String,StringBuilder,StringBuffer区别


    一、String,StringBuilder,StringBuffer的大概了解

    大家知道String,StringBuilder,StringBuffer三个的基本应用场景。

    • String会一直创建新对象,因此频繁创建对象的场景不适合用。
    • StringBuilder则可以避免这个情况,因此频繁对字符串操作的场景使用StringBuilder比较合适。
    • 但是StringBuilder并不是线程安全的,如果要线程安全,需要使用StringBuffer。

    二、为什么String会一直创建新对象?

    1     private final char value[];
    • String代码中,字符是存在一个 final 的 char value[]里面的。
    • 由于final指定了存储的内从是固定的,因此如果有append之类的操作的话要重新开辟新的内存。
    • 要注意的是即使 value[]是final的,它也是可以改变里面的内容的。

    下面这写法是正确的。不会报错。

    1 final char[] ss = {'a', 'b', 'c'};
    2 ss[0] = 'b';
    3 ss[1] = 'c';

    但是String类并没有提供这么一个接口能直接修改value数组。其中的replace是返回了一个新的String 对象。并不是在原先的数组上进行修改。

     1 public String replace(char oldChar, char newChar) {
     2         if (oldChar != newChar) {
     3             int len = value.length;
     4             int i = -1;
     5             char[] val = value; /* avoid getfield opcode */
     6 
     7             while (++i < len) {
     8                 if (val[i] == oldChar) {
     9                     break;
    10                 }
    11             }
    12             if (i < len) {
    13                 char buf[] = new char[len];
    14                 for (int j = 0; j < i; j++) {
    15                     buf[j] = val[j];
    16                 }
    17                 while (i < len) {
    18                     char c = val[i];
    19                     buf[i] = (c == oldChar) ? newChar : c;
    20                     i++;
    21                 }
    22                 return new String(buf, true);
    23             }
    24         }
    25         return this;
    26     }

    三、StringBuilder中的主要内容

    这个类继承了AbstractStringBuilder。AbstractStringBuilder里面封装了大部分内容。初始化大小为16个字符。

    1、相比较String中的value,这个不是final 类型的。

    char[] value;

    2、newCapacity方法。

    • 将原始的capacity*2+2
    • 判断新的容量是不是合法
    • 最大容量不会超过MAX_ARRAY_SIZE。MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8.
     1 private int newCapacity(int minCapacity) {
     2         // overflow-conscious code
     3         int newCapacity = (value.length << 1) + 2;
     4         if (newCapacity - minCapacity < 0) {
     5             newCapacity = minCapacity;
     6         }
     7         return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
     8             ? hugeCapacity(minCapacity)
     9             : newCapacity;
    10     }

    3、append方法

    其实最终调用了System.arrayCopy将append中的String value copy到了StringBuilder 中的 value。

    1 public AbstractStringBuilder append(StringBuffer sb) {
    2         if (sb == null)
    3             return appendNull();
    4         int len = sb.length();
    5         ensureCapacityInternal(count + len);
    6         sb.getChars(0, len, value, count);
    7         count += len;
    8         return this;
    9     }

    最终调用getChars方法。

     1 public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
     2         if (srcBegin < 0) {
     3             throw new StringIndexOutOfBoundsException(srcBegin);
     4         }
     5         if (srcEnd > value.length) {
     6             throw new StringIndexOutOfBoundsException(srcEnd);
     7         }
     8         if (srcBegin > srcEnd) {
     9             throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
    10         }
    11         System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    12     }

    四、StringBuffer中的主要内容

    这个类同样继承了AbstractStringBuilder。

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

    但是几乎所有的方法都加了同步。因此是线程安全的。

    1、append

    1 @Override
    2     public synchronized StringBuffer append(String str) {
    3         toStringCache = null;
    4         super.append(str);
    5         return this;
    6     }

    2、chartAt

    1 @Override
    2     public synchronized char charAt(int index) {
    3         if ((index < 0) || (index >= count))
    4             throw new StringIndexOutOfBoundsException(index);
    5         return value[index];
    6     }

    其中StringBuffer里面有个 char [] toStringCache。当调用toString的时候,这个就会缓存StringBuffer的内容。当对StringBuffer有修改的时候,这个数组就会设定为null。

    1     private transient char[] toStringCache;
    谢谢!
  • 相关阅读:
    C#单纯的字母数字ASCII码转换
    解析类型后加问号和双问号
    【转】composer autoload 自动加载性能优化指南
    【转】Laravel 三种中间件作用讲解
    【转】Laravel belongsTo 详解
    【转】docker-compose详解
    【转】laravel之Artisan命令操作Artisan Console
    【转】Shell中>/dev/null 2>&1 详解
    【转】docker-entrypoint.sh 文件的用处
    【转】解决Debian下sudo命令unable to initialize PAM问题
  • 原文地址:https://www.cnblogs.com/ylxn/p/10434713.html
Copyright © 2020-2023  润新知