博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
String StringBuffer StringBuilder StringJoiner的原理
阅读量:2713 次
发布时间:2019-05-13

本文共 11716 字,大约阅读时间需要 39 分钟。

1. String

先看String,上源码

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

String的本质就是char数组,JDK9之后改为byte数组了;是线程安全的原因,final修饰。

String是final class不能被继承。

String实现了Comparable接口可以直接比较

/**     * Compares two strings lexicographically.     * The comparison is based on the Unicode value of each character in     * the strings. The character sequence represented by this     * {@code String} object is compared lexicographically to the     * character sequence represented by the argument string. The result is     * a negative integer if this {@code String} object     * lexicographically precedes the argument string. The result is a     * positive integer if this {@code String} object lexicographically     * follows the argument string. The result is zero if the strings     * are equal; {@code compareTo} returns {@code 0} exactly when     * the {@link #equals(Object)} method would return {@code true}.     * 

* This is the definition of lexicographic ordering. If two strings are * different, then either they have different characters at some index * that is a valid index for both strings, or their lengths are different, * or both. If they have different characters at one or more index * positions, let k be the smallest such index; then the string * whose character at position k has the smaller value, as * determined by using the < operator, lexicographically precedes the * other string. In this case, {@code compareTo} returns the * difference of the two character values at position {@code k} in * the two string -- that is, the value: *

     * this.charAt(k)-anotherString.charAt(k)     * 
* If there is no index position at which they differ, then the shorter * string lexicographically precedes the longer string. In this case, * {@code compareTo} returns the difference of the lengths of the * strings -- that is, the value: *
     * this.length()-anotherString.length()     * 
* * @param anotherString the {@code String} to be compared. * @return the value {@code 0} if the argument string is equal to * this string; a value less than {@code 0} if this string * is lexicographically less than the string argument; and a * value greater than {@code 0} if this string is * lexicographically greater than the string argument. */ 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; }

原理是char循环,以最短的字符串size循环,逐个比较ASCII码,对于number类型的String,不能使用此方法比较,比如-1与-6,按照这种比对方式,-6>-1这显然不是我们想要的。

 

2. StringBuilder

public final class StringBuffer    extends AbstractStringBuilder    implements java.io.Serializable, CharSequence{    /**     * A cache of the last value returned by toString. Cleared     * whenever the StringBuffer is modified.     */    private transient char[] toStringCache;
abstract class AbstractStringBuilder implements Appendable, CharSequence {    /**     * The value is used for character storage.     */    char[] value;    /**     * The count is the number of characters used.     */    int count;

本质还是char数组,但是是可变的。看本质append方法

/**     * Appends the specified {@code CharSequence} to this     * sequence.     * 

* The characters of the {@code CharSequence} argument are appended, * in order, increasing the length of this sequence by the length of the * argument. * *

The result of this method is exactly the same as if it were an * invocation of this.append(s, 0, s.length()); * *

This method synchronizes on {@code this}, the destination * object, but does not synchronize on the source ({@code s}). * *

If {@code s} is {@code null}, then the four characters * {@code "null"} are appended. * * @param s the {@code CharSequence} to append. * @return a reference to this object. * @since 1.5 */ @Override public synchronized StringBuffer append(CharSequence s) { toStringCache = null; super.append(s); return this; }

线程安全的核心synchronized,深入了解append方法

super.append(s);
public AbstractStringBuilder append(CharSequence s) {        if (s == null)            return appendNull();        if (s instanceof String)            return this.append((String)s);        if (s instanceof AbstractStringBuilder)            return this.append((AbstractStringBuilder)s);        return this.append(s, 0, s.length());    }
/**     * Appends the specified string to this character sequence.     * 

* The characters of the {@code String} argument are appended, in * order, increasing the length of this sequence by the length of the * argument. If {@code str} is {@code null}, then the four * characters {@code "null"} are appended. *

* Let n be the length of this character sequence just prior to * execution of the {@code append} method. Then the character at * index k in the new character sequence is equal to the character * at index k in the old character sequence, if k is less * than n; otherwise, it is equal to the character at index * k-n in the argument {@code str}. * * @param str a string. * @return a reference to this object. */ 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; }

//扩容数组->新建数组,拷贝原数组至新数组ensureCapacityInternal(count + len);
/**     * For positive values of {@code minimumCapacity}, this method     * behaves like {@code ensureCapacity}, however it is never     * synchronized.     * If {@code minimumCapacity} is non positive due to numeric     * overflow, this method throws {@code OutOfMemoryError}.     */    private void ensureCapacityInternal(int minimumCapacity) {        // overflow-conscious code        if (minimumCapacity - value.length > 0) {            value = Arrays.copyOf(value,                    newCapacity(minimumCapacity));        }    }
/**     * Copies the specified array, truncating or padding with null characters (if necessary)     * so the copy has the specified length.  For all indices that are valid     * in both the original array and the copy, the two arrays will contain     * identical values.  For any indices that are valid in the copy but not     * the original, the copy will contain '\\u000'.  Such indices     * will exist if and only if the specified length is greater than that of     * the original array.     *     * @param original the array to be copied     * @param newLength the length of the copy to be returned     * @return a copy of the original array, truncated or padded with null characters     *     to obtain the specified length     * @throws NegativeArraySizeException if newLength is negative     * @throws NullPointerException if original is null     * @since 1.6     */    public static char[] copyOf(char[] original, int newLength) {        char[] copy = new char[newLength];        System.arraycopy(original, 0, copy, 0,                         Math.min(original.length, newLength));        return copy;    }
public static native void arraycopy(Object src,  int  srcPos,                                        Object dest, int destPos,                                        int length);
本质是调用native复制数组str.getChars(0, len, value, count);
/**     * Copies characters from this string into the destination character     * array.     * 

* The first character to be copied is at index {@code srcBegin}; * the last character to be copied is at index {@code srcEnd-1} * (thus the total number of characters to be copied is * {@code srcEnd-srcBegin}). The characters are copied into the * subarray of {@code dst} starting at index {@code dstBegin} * and ending at index: *

     *     dstBegin + (srcEnd-srcBegin) - 1     * 
* * @param srcBegin index of the first character in the string * to copy. * @param srcEnd index after the last character in the string * to copy. * @param dst the destination array. * @param dstBegin the start offset in the destination array. * @exception IndexOutOfBoundsException If any of the following * is true: *
  • {@code srcBegin} is negative. *
  • {@code srcBegin} is greater than {@code srcEnd} *
  • {@code srcEnd} is greater than the length of this * string *
  • {@code dstBegin} is negative *
  • {@code dstBegin+(srcEnd-srcBegin)} is larger than * {@code dst.length}
*/ public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > value.length) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } //数组拷贝 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); }

 

3. StringBuilder

public final class StringBuilder    extends AbstractStringBuilder    implements java.io.Serializable, CharSequence
public StringBuilder append(CharSequence s) {        super.append(s);        return this;    }

跟StringBuffer一样,只是没有同步罢了

 

4. StringJoiner

public final class StringJoiner {    private final String prefix;    private final String delimiter;    private final String suffix;    /*     * StringBuilder value -- at any time, the characters constructed from the     * prefix, the added element separated by the delimiter, but without the     * suffix, so that we can more easily add elements without having to jigger     * the suffix each time.     */    private StringBuilder value;    /*     * By default, the string consisting of prefix+suffix, returned by     * toString(), or properties of value, when no elements have yet been added,     * i.e. when it is empty.  This may be overridden by the user to be some     * other value including the empty String.     */    private String emptyValue;

可以看出本质是StringBuilder,封装了分隔符,前后缀,便于我们append

初始化前后缀,在构造的时候

public StringJoiner(CharSequence delimiter,                        CharSequence prefix,                        CharSequence suffix) {        Objects.requireNonNull(prefix, "The prefix must not be null");        Objects.requireNonNull(delimiter, "The delimiter must not be null");        Objects.requireNonNull(suffix, "The suffix must not be null");        // make defensive copies of arguments        this.prefix = prefix.toString();        this.delimiter = delimiter.toString();        this.suffix = suffix.toString();        this.emptyValue = this.prefix + this.suffix;    }

append的时候自动加入分隔符

private StringBuilder prepareBuilder() {        if (value != null) {            value.append(delimiter);        } else {            value = new StringBuilder().append(prefix);        }        return value;    }

总结

其实这些都很简单,看看源码就可以知道原理,可以简化使用,加快效率。

 

 

转载地址:http://oslvd.baihongyu.com/

你可能感兴趣的文章
LeetCode 62. Unique Paths LeetCode 63 Unique Paths II 不同的路径之二
查看>>
LeetCode 66. Plus One
查看>>
LeetCode 74. Search a 2D Matrix
查看>>
【已解决】 78. Subsets【39、40未解决】
查看>>
创建第一个android项目
查看>>
Excel 使用过程中碰到的问题处理
查看>>
阿里云负载均衡SLB--报错502 Bad Gateway 的解决方案
查看>>
Monte Carlo 方法求解π的近似值
查看>>
一些python学习的基本操作(持续更新中)
查看>>
Fluxion安装教程
查看>>
网络安全基础知识
查看>>
最详细 vsphere创建Windows service虚拟机,并安装VMware Tools 进行配置
查看>>
【html/css】如何设置HTML span 的宽度
查看>>
ubuntu12.10更新包后的问题
查看>>
【web开发】EL表达式的一些用法小结
查看>>
【mysql】关于命令load data local infile
查看>>
我是如何在5个月内找到一份薪水翻番的工作的?
查看>>
如何选择更适合你的 Linux 发行版?
查看>>
数据分析师必知必会的7款Python工具
查看>>
又到招聘季,说说网络招聘的那些坑
查看>>