《Thinking in Java》读书笔记——第13章 字 符 串

1. 不可变String

String对象都是不可变的:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    
    
    /** The value is used for character storage. */
    private final char value[];

很显然,String的值在内部是使用char数组来保存,并且是final类型,这就意味着在初始化的时候被赋值将不会更改。String类中每一个看起来会修改String值得方法,实际上都是创建了一个新的String对象罢了。

2.String、StringBuffer和StringBuilder

2.1 String常用api:

  • length() : 返回String中字符个数。
  • charAt() :返回i索引上的char
  • equals() : 判断两个字符串是否相等:如果引用地址相同则直接返回true,否则,如果是字符串类型则将其转化为char数组逐一比对。
    public boolean equals(Object anObject) {
    
    
        if (this == anObject) {
    
    
            return true;
        }
        if (anObject instanceof String) {
    
    
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
    
    
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
    
    
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
  • compareTo() : 按照词典顺序比较String内容,返回调用者(this)与参数的第一个不相同字符的ascii码差值 。如果在相同返回长度差值。
    public int compareTo(String anotherString) {
    
    
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
    
    
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
    
    
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
  • contains() : 调用者(this)是否包含参数内容,jdk中调用indexOf方法
public boolean contains(CharSequence s) {
    
    
        return indexOf(s.toString()) > -1;
    }
  • indexOf() : 返回此参数在该字符串中的索引,不存在则返回-1.
    传入的参数可以是char,char和起始查询位置,或者是String,String和起始查询位置,查询方法是第一个指针先查找第一个匹配字符的起始位置然后第二个指针向后查找出整个字符串,不匹配则i++继续查找
    public int indexOf(String str) {
    
    
        return indexOf(str, 0);
    }

    public int indexOf(String str, int fromIndex) {
    
    
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }

   /**
     * Code shared by String and StringBuffer to do searches. The
     * source is the character array being searched, and the target
     * is the string being searched for.
     *
     * @param   source       the characters being searched.
     * @param   sourceOffset offset of the source string.
     * @param   sourceCount  count of the source string.
     * @param   target       the characters being searched for.
     * @param   targetOffset offset of the target string.
     * @param   targetCount  count of the target string.
     * @param   fromIndex    the index to begin searching from.
     */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
    
    
        if (fromIndex >= sourceCount) {
    
    
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
    
    
            fromIndex = 0;
        }
        if (targetCount == 0) {
    
    
            return fromIndex;
        }

        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i <= max; i++) {
    
    
            /* Look for first character. */
            if (source[i] != first) {
    
    
                while (++i <= max && source[i] != first);
            }

            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
    
    
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);

                if (j == end) {
    
    
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }
  • substring() : 可以注意的是string是小写,用于截取字符串,传入的参数可以是起始位置,或者是起始位置和终止位置。实际上就是通过String的构造函数重新生成一个字符串。
    public String substring(int beginIndex, int endIndex) {
    
    
        if (beginIndex < 0) {
    
    
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
    
    
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
    
    
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
  • trim() : 删除两端空白字符。
  • valueOf() : 转换成为字符串,返回的是原始值,和toString()的差别是toString()更强调的是对对象的反映。

2.2 StringBuilder 和 StringBuffer

2.2.1StringBuilder

StringBuilder 是可变字符串,是线程不安全,但是也是执行速度更快的,默认初始容量为16,当然你也可以在构造函数中传入初始容量,初始的字符串等。

public StringBuilder() {
    
    super(16);}

public StringBuilder(int capacity) {
    
    super(capacity);}

public StringBuilder(String str) {
    
    
        super(str.length() + 16);
         append(str);
         }    

空间不足时扩容则是原容量向左移动一位再加2相当于 原容量乘二再加二

    private int newCapacity(int minCapacity) {
    
    
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
    
    
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }
  • StringBuilder常用的方法有:append()追加字符串,和reverse()翻转字符串等。

2.2.2 StringBuffer

StringBuffer也是可变字符串,是线程安全的,但是执行速度不如StringBuilder

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

大多数方法加了 synchronized 修饰,保证了线程安全,从而减低了执行速度。

2.2.3 总结

  1. 如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。
  2. 相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。所以确保你的模块不会运行在多线程模式下,才可以采用 StringBuilder;否则还是用 StringBuffer。
  3. 为了获得更好的性能,在构造 StringBuffer 或 StringBuilder 时应尽可能指定它们的容量。如果确定长度不超过16,则可以忽略。

猜你喜欢

转载自blog.csdn.net/weixin_48922154/article/details/113266381