java--String源码解析

String简介

在java.lang包中,此类被final修饰,表示String的对象是不可变量,不可继承,多线程线程不安全。
String类实现了Serizlizable,Comparable, CharSequence接口。
Serizlizable接口没有任何方法和域,仅用于标识序列化的语意,实现此接口的类是可序列化的,是java提供的通用数据保存和读取的接口。

String的构造函数

String() 
初始化新创建的 String对象,使其表示空字符序列。  
String(byte[] bytes) 
通过使用平台的默认字符集解码指定的字节数组来构造新的 StringString(byte[] bytes, Charset charset) 
构造一个新的String由指定用指定的字节的数组解码charset 。  
String(byte[] ascii, int hibyte) 
已弃用 
此方法无法将字节正确转换为字符。 从JDK 1.1开始,首选的方法是通过String构造函数获取Charset ,字符集名称,或者使用平台的默认字符集。  
String(byte[] bytes, int offset, int length) 
通过使用平台的默认字符集解码指定的字节子阵列来构造新的 StringString(byte[] bytes, int offset, int length, Charset charset) 
构造一个新的String通过使用指定的指定字节子阵列解码charset 。  
String(byte[] ascii, int hibyte, int offset, int count) 
已弃用 
此方法无法将字节正确转换为字符。 从JDK 1.1开始,首选的方式是通过String构造函数获取Charset ,字符集名称,或使用平台的默认字符集。  
String(byte[] bytes, int offset, int length, String charsetName) 
构造一个新的 String通过使用指定的字符集解码指定的字节子阵列。  
String(byte[] bytes, String charsetName) 
构造一个新的String由指定用指定的字节的数组解码charset 。  
String(char[] value) 
分配一个新的 String ,以便它表示当前包含在字符数组参数中的字符序列。  
String(char[] value, int offset, int count) 
分配一个新的 String ,其中包含字符数组参数的子阵列中的字符。  
String(int[] codePoints, int offset, int count) 
分配一个新的 String ,其中包含 Unicode code point数组参数的子阵列中的 字符 。  
String(String original) 
初始化新创建的String对象,使其表示与参数相同的字符序列; 换句话说,新创建的字符串是参数字符串的副本。  
String(StringBuffer buffer) 
分配一个新的字符串,其中包含当前包含在字符串缓冲区参数中的字符序列。  
String(StringBuilder builder) 
分配一个新的字符串,其中包含当前包含在字符串构建器参数中的字符序列。

String的API

char charAt(int index) 
返回 char指定索引处的值。  
int codePointAt(int index) 
返回指定索引处的字符(Unicode代码点)。  
int codePointBefore(int index) 
返回指定索引之前的字符(Unicode代码点)。  
int codePointCount(int beginIndex, int endIndex) 
返回此 String指定文本范围内的Unicode代码点数。  
int compareTo(String anotherString) 
按字典顺序比较两个字符串。  
int compareToIgnoreCase(String str) 
按字典顺序比较两个字符串,忽略病例差异。  
String concat(String str) 
将指定的字符串连接到该字符串的末尾。  
boolean contains(CharSequence s) 
当且仅当此字符串包含指定的char值序列时才返回trueboolean contentEquals(CharSequence cs) 
将此字符串与指定的CharSequence进行 CharSequence 。  
boolean contentEquals(StringBuffer sb) 
将此字符串与指定的StringBuffer进行 StringBuffer 。  
static String copyValueOf(char[] data) 
相当于 valueOf(char[]) 。  
static String copyValueOf(char[] data, int offset, int count) 
相当于 valueOf(char[], int, int) 。  
boolean endsWith(String suffix) 
测试此字符串是否以指定的后缀结尾。  
boolean equals(Object anObject) 
将此字符串与指定对象进行比较。  
boolean equalsIgnoreCase(String anotherString) 
将此 String与其他 String比较,忽略案例注意事项。  
static String format(Locale l, String format, Object... args) 
使用指定的区域设置,格式字符串和参数返回格式化的字符串。  
static String format(String format, Object... args) 
使用指定的格式字符串和参数返回格式化的字符串。  
byte[] getBytes() 
使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中。  
byte[] getBytes(Charset charset) 
使用给定的charset将该String编码为字节序列,将结果存储到新的字节数组中。  
void getBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin) 
已弃用 
此方法无法将字符正确转换为字节。 从JDK 1.1开始,首选的方法是通过getBytes()方法,该方法使用平台的默认字符集。  
byte[] getBytes(String charsetName) 
使用命名的字符集将此 String编码为字节序列,将结果存储到新的字节数组中。  
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 
将此字符串中的字符复制到目标字符数组中。  
int hashCode() 
返回此字符串的哈希码。  
int indexOf(int ch) 
返回指定字符第一次出现的字符串内的索引。  
int indexOf(int ch, int fromIndex) 
返回指定字符第一次出现的字符串内的索引,以指定的索引开始搜索。  
int indexOf(String str) 
返回指定子字符串第一次出现的字符串内的索引。  
int indexOf(String str, int fromIndex) 
返回指定子串的第一次出现的字符串中的索引,从指定的索引开始。  
String intern() 
返回字符串对象的规范表示。  
boolean isEmpty() 
返回 true如果,且仅当 length()为 0static String join(CharSequence delimiter, CharSequence... elements) 
返回一个新的字符串,由 CharSequence elements的副本组成,并附有指定的delimiter的 delimiter 。  
static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) 
返回一个新 String的副本组成 CharSequence elements与指定的副本一起加入 delimiter 。  
int lastIndexOf(int ch) 
返回指定字符的最后一次出现的字符串中的索引。  
int lastIndexOf(int ch, int fromIndex) 
返回指定字符的最后一次出现的字符串中的索引,从指定的索引开始向后搜索。  
int lastIndexOf(String str) 
返回指定子字符串最后一次出现的字符串中的索引。  
int lastIndexOf(String str, int fromIndex) 
返回指定子字符串的最后一次出现的字符串中的索引,从指定索引开始向后搜索。  
int length() 
返回此字符串的长度。  
boolean matches(String regex) 
告诉这个字符串是否匹配给定的 regular expression 。  
int offsetByCodePoints(int index, int codePointOffset) 
返回此 String内的指数,与 index codePointOffset代码点。  
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 
测试两个字符串区域是否相等。  
boolean regionMatches(int toffset, String other, int ooffset, int len) 
测试两个字符串区域是否相等。  
String replace(char oldChar, char newChar) 
返回从替换所有出现的导致一个字符串 oldChar在此字符串 newChar 。  
String replace(CharSequence target, CharSequence replacement) 
将与字面目标序列匹配的字符串的每个子字符串替换为指定的字面替换序列。  
String replaceAll(String regex, String replacement) 
用给定的替换替换与给定的 regular expression匹配的此字符串的每个子字符串。  
String replaceFirst(String regex, String replacement) 
用给定的替换替换与给定的 regular expression匹配的此字符串的第一个子字符串。  
String[] split(String regex) 
将此字符串分割为给定的 regular expression的匹配。  
String[] split(String regex, int limit) 
将这个字符串拆分为给定的 regular expression的匹配。  
boolean startsWith(String prefix) 
测试此字符串是否以指定的前缀开头。  
boolean startsWith(String prefix, int toffset) 
测试在指定索引处开始的此字符串的子字符串是否以指定的前缀开头。  
CharSequence subSequence(int beginIndex, int endIndex) 
返回一个字符序列,该序列是该序列的子序列。  
String substring(int beginIndex) 
返回一个字符串,该字符串是此字符串的子字符串。  
String substring(int beginIndex, int endIndex) 
返回一个字符串,该字符串是此字符串的子字符串。  
char[] toCharArray() 
将此字符串转换为新的字符数组。  
String toLowerCase() 
将所有在此字符 String使用默认语言环境的规则,以小写。  
String toLowerCase(Locale locale) 
将所有在此字符 String ,以降低使用给定的规则情况下 Locale 。  
String toString() 
此对象(已经是字符串!)本身已被返回。  
String toUpperCase() 
将所有在此字符 String使用默认语言环境的规则大写。  
String toUpperCase(Locale locale) 
将所有在此字符 String使用给定的规则,大写 Locale 。  
String trim() 
返回一个字符串,其值为此字符串,并删除任何前导和尾随空格。  
static String valueOf(boolean b) 
返回 boolean参数的字符串 boolean形式。  
static String valueOf(char c) 
返回 char参数的字符串 char形式。  
static String valueOf(char[] data) 
返回 char数组参数的字符串 char形式。  
static String valueOf(char[] data, int offset, int count) 
返回 char数组参数的特定子阵列的字符串 char形式。  
static String valueOf(double d) 
返回 double参数的字符串 double形式。  
static String valueOf(float f) 
返回 float参数的字符串 float形式。  
static String valueOf(int i) 
返回 int参数的字符串 int形式。  
static String valueOf(long l) 
返回 long参数的字符串 long形式。  
static String valueOf(Object obj) 
返回 Object参数的字符串 Object形式。

String的继承关系

public final class String extends Object implements Serializable, Comparable<String>, CharSequence

String源码解析

为了更了解String的原理,下面对String源码代码作出分析。String源码代码

package java.util;
public final class String 
    extends Object 
        implements Serializable, Comparable<String>, CharSequence
{
//使用字符数组存放字符串
private final char value[];
// Default to 0  存放哈希值
private int hash; 
/**
    * 这是一个经常会使用的String的无参构造函数.
    * 默认将""空字符串的value赋值给实例对象的value,也是空字符
    * 相当于深拷贝了空字符串""
    */
    public String() {
        this.value = "".value;
    }

    /** 
    * 这是一个有参构造函数,参数为一个String对象
    * 将形参的value和hash赋值给实例对象作为初始化
    * 相当于深拷贝了一个形参String对象
    */
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

    /** 
    * 这是一个有参构造函数,参数为一个char字符数组
    * 意义就是通过字符数组去构建一个新的String对象
    */
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

    /**    
    * 这是一个有参构造函数,参数为char字符数组,offset(起始位置,偏移量),count(个数)
    * 作用就是在char数组的基础上,从offset位置开始计数count个,构成一个新的String的字符串
    * 意义就类似于截取count个长度的字符集合构成一个新的String对象
    */
    public String(char value[], int offset, int count) {
        if (offset < 0) {        //如果起始位置小于0,抛异常
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {     //如果个数小于0,抛异常
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {      //在count = 0的前提下,如果offset<=len,则返回""
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        //如果起始位置>字符数组长度 - 个数,则无法截取到count个字符,抛异常
        if (offset > value.length - count) { 
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        //重点,从offset开始,截取到offset+count位置(不包括offset+count位置)
        this.value = Arrays.copyOfRange(value, offset, offset+count); 
    }

    /** 
    * 这是一个有参构造函数,参数为int字符数组,offset(起始位置,偏移量),count(个数)
    * 作用跟上面构造函数差不多,但是传入的不是char字符数组,而是int数组。
    * 而int数组的元素则是字符对应的ASCII整数值
    * 例子:new String(new int[]{97,98,99},0,3);   output: abc
    */
    public String(int[] codePoints, int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= codePoints.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > codePoints.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }  
        //以上都是为了处理offset和count的正确性,如果有错,则抛异常

        final int end = offset + count;

        // Pass 1: Compute precise size of char[]
        int n = count;
        for (int i = offset; i < end; i++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                continue;
            else if (Character.isValidCodePoint(c))
                n++;
            else throw new IllegalArgumentException(Integer.toString(c));
        }

        //上面关于BMP什么的,我暂时也没看懂,猜想关于验证int数据的正确性,通过上面的测试就进入下面的算法

        // Pass 2: Allocate and fill in char[]
        final char[] v = new char[n];

        for (int i = offset, j = 0; i < end; i++, j++) {  //从offset开始,到offset + count
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                v[j] = (char)c;   //将Int类型显式缩窄转换为char类型
            else
                Character.toSurrogates(c, v, j++);
        }

        this.value = v; //最后将得到的v赋值给String对象的value,完成初始化
    }


    /****这里把被标记为过时的构造函数去掉了***/

    /** 
    * 这是一个有参构造函数,参数为byte数组,offset(起始位置,偏移量),长度,和字符编码格式
    * 就是传入一个byte数组,从offset开始截取length个长度,其字符编码格式为charsetName,如UTF-8
    * 例子:new String(bytes, 2, 3, "UTF-8");
    */
    public String(byte bytes[], int offset, int length, String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(charsetName, bytes, offset, length);
    }

    /** 
    * 类似上面构造器
    */
    public String(byte bytes[], int offset, int length, Charset charset) {
        if (charset == null)
            throw new NullPointerException("charset");
        checkBounds(bytes, offset, length);
        this.value =  StringCoding.decode(charset, bytes, offset, length);
    }

    /** 
    * 这是一个有参构造函数,参数为byte数组和字符集编码
    * 用charsetName的方式构建byte数组成一个String对象
    */
    public String(byte bytes[], String charsetName)
            throws UnsupportedEncodingException {
        this(bytes, 0, bytes.length, charsetName);
    }

    /** 
    * 类似上面构造器
    */
    public String(byte bytes[], Charset charset) {
        this(bytes, 0, bytes.length, charset);
    }

    /** 
    * 这是一个有参构造函数,参数为byte数组,offset(起始位置,偏移量),length(个数)
    * 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。
    * 
    */
    public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }

    /** 
    * 这是一个有参构造函数,参数为byte数组
    * 通过使用平台默认字符集编码解码传入的byte数组,构造成一个String对象,不需要截取
    * 
    */
    public String(byte bytes[]) {
        this(bytes, 0, bytes.length);
    }

    /** 
    * 有参构造函数,参数为StringBuffer类型
    * 就是将StringBuffer构建成一个新的String,比较特别的就是这个方法有synchronized锁
    * 同一时间只允许一个线程对这个buffer构建成String对象
    */
    public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); //使用拷贝的方式
        }
    }

    /** 
    * 有参构造函数,参数为StringBuilder
    * 同上面构造器差不多,只不过是StringBuilder的版本,差别就是没有实现线程安全
    */
    public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }

    /** 
    * 这个构造函数比较特殊,有用的参数只有char数组value,是一个不对外公开的构造函数,没有访问修饰符
    * 加入这个share的只是为了区分于String(char[] value)方法,用于重载,功能类似于03,我也在03表示过疑惑。
    * 为什么提供这个方法呢,因为性能好,不需要拷贝。为什么不对外提供呢?因为对外提供会打破value为不变数组的限制。
    * 如果对外提供这个方法让String与外部的value产生关联,如果修改外不的value,会影响String的value。所以不能
    * 对外提供
    */
    String(char[] value, boolean share) {
        // assert share : "unshared not supported";
        this.value = value;
    }

/**
*所以String的长度就是一个value的长度
*/

  public int length() {      
        return value.length;
    }

/**
*当char数组的长度为0,则代表String为"",空字符串
*/
    public boolean isEmpty() {      
    return value.length == 0;
    }

/**
   * 返回String对象的char数组index位置的元素
   */
   public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {   //index不允许小于0,不允许大于等于String的长度
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index]; //返回
    }

   /**
    * 返回String对象的char数组index位置的元素的ASSIC码(int类型)
    */
    public int codePointAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointAtImpl(value, index, value.length);
    }

   /**
    * 返回index位置元素的前一个元素的ASSIC码(int型)
    */
    public int codePointBefore(int index) {
        int i = index - 1;  //获得index前一个元素的索引位置
        if ((i < 0) || (i >= value.length)) { //所以,index不能等于0,因为i = 0 - 1 = -1
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointBeforeImpl(value, index, 0);
    }

   /**
    * 方法返回的是代码点个数,是实际上的字符个数,功能类似于length()
    * 对于正常的String来说,length方法和codePointCount没有区别,都是返回字符个数。
    * 但当String是Unicode类型时则有区别了。
    * 例如:String str = “/uD835/uDD6B” (即使 'Z' ), length() = 2 ,codePointCount() = 1 
    */
    public int codePointCount(int beginIndex, int endIndex) {
        if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {
            throw new IndexOutOfBoundsException();
        }
        return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
    }

   /**
    * 也是相对Unicode字符集而言的,从index索引位置算起,偏移codePointOffset个位置,返回偏移后的位置是多少
    * 例如,index = 2 ,codePointOffset = 3 ,maybe返回 5 
    */
    public int offsetByCodePoints(int index, int codePointOffset) {
        if (index < 0 || index > value.length) {
            throw new IndexOutOfBoundsException();
        }
        return Character.offsetByCodePointsImpl(value, 0, value.length,
                index, codePointOffset);
    }
/**
    * 这是一个不对外的方法,是给String内部调用的,因为它是没有访问修饰符的,只允许同一包下的类访问
    * 参数:dst[]是目标数组,dstBegin是目标数组的偏移量,既要复制过去的起始位置(从目标数组的什么位置覆盖)
    * 作用就是将String的字符数组value整个复制到dst字符数组中,在dst数组的dstBegin位置开始拷贝
    * 
    */
    void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }

   /**
    * 得到char字符数组,原理是getChars() 方法将一个字符串的字符复制到目标字符数组中。 
    * 参数:srcBegin是原始字符串的起始位置,srcEnd是原始字符串要复制的字符末尾的后一个位置(既复制区域不包括srcEnd)
    * dst[]是目标字符数组,dstBegin是目标字符的复制偏移量,复制的字符从目标字符数组的dstBegin位置开始覆盖。
    */
    public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {           //如果srcBegin小于,抛异常
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
    *    if (srcEnd > value.length) {  //如果srcEnd大于字符串的长度,抛异常
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {      //如果原始字符串其实位置大于末尾位置,抛异常
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }


   /****去除被标记过时的方法****/

   /**
    * 获得charsetName编码格式的bytes数组
    */
    public byte[] getBytes(String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null) throw new NullPointerException();
        return StringCoding.encode(charsetName, value, 0, value.length);
    }

   /**
    * 与上个方法类似,但charsetName和charset的区别,我还没搞定,搞懂来再更新
    */
    public byte[] getBytes(Charset charset) {
        if (charset == null) throw new NullPointerException();
        return StringCoding.encode(charset, value, 0, value.length);
    }

    /**
    * 使用平台默认的编码格式获得bytes数组
    */
    public byte[] getBytes() {
        return StringCoding.encode(value, 0, value.length);
    }
/**
* String的equals方法,重写了Object的equals方法(区分大小写)
* 比较的是两个字符串的值是否相等
* 参数是一个Object对象,而不是一个String对象。这是因为重写的是Object的equals方法,所以是Object
* 如果是String自己独有的方法,则可以传入String对象,不用多此一举
* 
* 实例:str1.equals(str2)
*/
public boolean equals(Object anObject) {
        if (this == anObject) {   //首先判断形参str2是否跟当前对象str1是同一个对象,既比较地址是否相等
            return true;          //如果地址相等,那么自然值也相等,毕竟是同一个字符串对象
        }
        if (anObject instanceof String) {  //判断str2对象是否是一个String类型,过滤掉非String类型的比较
            String anotherString = (String)anObject; //如果是String类型,转换为String类型
            int n = value.length;                    //获得当前对象str1的长度
            if (n == anotherString.value.length) {   //比较str1的长度和str2的长度是否相等
                                                     //如是进入核心算法
                char v1[] = value;                   //v1为当前对象str1的值,v2为参数对象str2的值
                char v2[] = anotherString.value;
                int i = 0;                           //就类似于for的int i =0的作用,因为这里使用while
                while (n-- != 0) {                   //每次循环长度-1,直到长度消耗完,循环结束 
                    if (v1[i] != v2[i])              //同索引位置的字符元素逐一比较
                        return false;                //只要有一个不相等,则返回false
                    i++;
                }
                return true;                         //如比较期间没有问题,则说明相等,返回true
            }
        }
        return false;
    }

    /**
    * 这也是一个String的equals方法,与上一个方法不用,该方法(不区分大小写),从名字也能看出来
    * 是对String的equals方法的补充。
    * 这里参数这是一个String对象,而不是Object了,因为这是String本身的方法,不是重写谁的方法
    */
    public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true                   //一样,先判断是否为同一个对象
                : (anotherString != null) 
                && (anotherString.value.length == value.length) //再判断长度是否相等
                && regionMatches(true, 0, anotherString, 0, value.length);  //再执行regionMatchs方法 
    }


    /**
    * 这是一个公有的比较方法,参数是StringBuffer类型
    * 实际调用的是contentEquals(CharSequence cs)方法,可以说是StringBuffer的特供版
    */
    public boolean contentEquals(StringBuffer sb) {
        return contentEquals((CharSequence)sb);
    }

    /**
    * 这是一个私有方法,特供给比较StringBuffer和StringBuilder使用的。
    * 比如在contentEquals方法中使用,参数是AbstractStringBuilder抽象类的子类
    *
    */
    private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
        char v1[] = value;               //当前String对象的值
        char v2[] = sb.getValue();       //AbstractStringBuilder子类对象的值
        int n = v1.length;               //后面就不说了,其实跟equals方法是一样的,只是少了一些判断
        if (n != sb.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != v2[i]) {
                return false;
            }
        }
        return true;
    }

    /**
    * 这是一个常用于String对象跟StringBuffer和StringBuilder比较的方法
    * 参数是StringBuffer或StringBuilder或String或CharSequence
    * StringBuffer和StringBuilder和String都实现了CharSequence接口
    */
    public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {   //如果是AbstractStringBuilder抽象类或其子类
            if (cs instanceof StringBuffer) {        //如果是StringBuffer类型,进入同步块
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {                                 //如果是StringBuilder类型,则进入非同步块
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }

        /***下面就是String和CharSequence类型的比较算法*****/
        // Argument is a String
        if (cs instanceof String) {                    
            return equals(cs);
        }
        // Argument is a generic CharSequence
        char v1[] = value;
        int n = v1.length;
        if (n != cs.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != cs.charAt(i)) {
                return false;
            }
        }
        return true;
    }
/**
    * 这是一个类似于equals的方法,比较的是字符串的片段,也即是部分区域的比较
    * toffset是当前字符串的比较起始位置(偏移量),other是要比较的String对象参数,ooffset是要参数String的比较片段起始位置,len是两个字符串要比较的片段的长度大小
    * 
    * 例子:String str1 = "0123456",Str2 = "0123456789"; 
    * str1.regionMatchs(0,str2,0,6);意思是str1从0位置开始于str2的0位置开始比较6个长度的字符串片段
    * 相等则返回 true,不等返回false 
    */
    public boolean regionMatches(int toffset, String other, int ooffset,
            int len) {
        char ta[] = value;  //当前对象的值
        int to = toffset;   //当前对象的比较片段的起始位置,既偏移量
        char pa[] = other.value;  //参数,既比较字符串的值
        int po = ooffset;         //比较字符串的起始位置
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0)  //起始位置不小于0或起始位置不大于字符串长度 - 片段长度,大于就截取不到这么长的片段了
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;      //惊讶脸,居然不是抛异常,而是返回false
        }
        while (len-- > 0) {               //使用while循环,当然也可以使for循环
            if (ta[to++] != pa[po++]) {   //片段区域的字符元素逐个比较
                return false;
            }
        }
        return true;
    }

    /**
    * 这个跟上面的方法一样,只不过多了一个参数,既ignoreCase,既是否为区分大小写。
    * 是equalsIgnoreCase()方法的片段比较版本,实际上equalsIgnoreCase()也是调用regionMatches函数
    */  
    public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        //上面的解释同上
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            if (ignoreCase) {   //当ignoreCase为true时,既忽视大小写时
                // If characters don't match but case may be ignored,
                // try converting both characters to uppercase.
                // If the results match, then the comparison scan should
                // continue.
                char u1 = Character.toUpperCase(c1);   //片段中每个字符转换为大写
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) { //大写比较一次,如果相等则不执行下面的语句,进入下一个循环
                    continue;
                }
                // Unfortunately, conversion to uppercase does not work properly
                // for the Georgian alphabet, which has strange rules about case
                // conversion.  So we need to make one last check before
                // exiting.
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                 //每个字符换行成小写比较一次
                    continue;
                }
            }
            return false;
        }
        return true;
    }
/**
    * 这是一个比较字符串中字符大小的函数,因为String实现了Comparable<String>接口,所以重写了compareTo方法
    * Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。
    * 实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
    * 
    * 参数是需要比较的另一个String对象
    * 返回的int类型,正数为大,负数为小,是基于字符的ASSIC码比较的
    * 
    */
    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;                                //相当于for的int k = 0,就是为while循环的数组服务的
        while (k < lim) {                         //当当前索引小于两个字符串中较短字符串的长度时,循环继续
            char c1 = v1[k];          //获得当前对象的字符
            char c2 = v2[k];          //获得比较对象的字符
            if (c1 != c2) {           //从前向后遍历,只要其实一个不相等,返回字符ASSIC的差值,int类型
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;           //如果两个字符串同样位置的索引都相等,返回长度差值,完全相等则为0
    }

    /**
    *  这时一个类似compareTo功能的方法,但是不是comparable接口的方法,是String本身的方法
    *  使用途径,我目前只知道可以用来不区分大小写的比较大小,但是不知道如何让它被工具类Collections和Arrays运用
    *
    */
    public int compareToIgnoreCase(String str) {
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }

    /**
    * 这是一个饿汉单例模式,是String类型的一个不区分大小写的比较器
    * 提供给Collections和Arrays的sort方法使用
    * 例如:Arrays.sort(strs,String.CASE_INSENSITIVE_ORDER);
    * 效果就是会将strs字符串数组中的字符串对象进行忽视大小写的排序
    *
    */
    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();

    /**
    * 这一个私有的静态内部类,只允许String类本身调用
    * 实现了序列化接口和比较器接口,comparable接口和comparator是有区别的
    * 重写了compare方法,该静态内部类实际就是一个String类的比较器
    *
    */
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();                 //s1字符串的长度
            int n2 = s2.length();                 //s2字符串的长度
            int min = Math.min(n1, n2);           //获得最小长度 
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);           //逐一获得字符串i位置的字符
                char c2 = s2.charAt(i);
                if (c1 != c2) {                   //部分大小写比较一次
                    c1 = Character.toUpperCase(c1);    //转换大写比较一次
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);  //转换小写比较一次
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {                  //返回字符差值
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;  //如果字符相等,但是长度不等,则返回长度差值,短的教小,所以小-大为负数
        }

        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }

/**
    * 作用就是当前对象[toffset,toffset + prefix.value.lenght]区间的字符串片段等于prefix
    * 也可以说当前对象的toffset位置开始是否以prefix作为前缀
    * prefix是需要判断的前缀字符串,toffset是当前对象的判断起始位置
    */
    public boolean startsWith(String prefix, int toffset) {
        char ta[] = value;     //获得当前对象的值
        int to = toffset;      //获得需要判断的起始位置,偏移量
        char pa[] = prefix.value; //获得前缀字符串的值
        int po = 0;
        int pc = prefix.value.length;
        // Note: toffset might be near -1>>>1.
        if ((toffset < 0) || (toffset > value.length - pc)) {  //偏移量不能小于0且能截取pc个长度
                    return false;  //不能则返回false
        }
        while (--pc >= 0) {                  //循环pc次,既prefix的长度
            if (ta[to++] != pa[po++]) {      //每次比较当前对象的字符串的字符是否跟prefix一样
                return false;                //一样则pc--,to++,po++,有一个不同则返回false
            }
        }
        return true;  //没有不一样则返回true,当前对象是以prefix在toffset位置做为开头
    }

    /**
    * 判断当前字符串对象是否以字符串prefix起头
    * 是返回true,否返回fasle
    */
    public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
    }

    /**
    * 判断当前字符串对象是否以字符串prefix结尾
    * 是返回true,否返回fasle
    */
    public boolean endsWith(String suffix) {
        //suffix是需要判断是否为尾部的字符串。
        //value.length - suffix.value.length是suffix在当前对象的起始位置
        return startsWith(suffix, value.length - suffix.value.length); 
    }
/**
   * 这是String字符串重写了Object类的hashCode方法。
   * 给由哈希表来实现的数据结构来使用,比如String对象要放入HashMap中。
   * 如果没有重写HashCode,或HaseCode质量很差则会导致严重的后果,既不靠谱的后果
   *
   */
   public int hashCode() {
        int h = hash;  //hash是属性字段,是成员变量,所以默认为0
        if (h == 0 && value.length > 0) { //如果hash为0,且字符串对象长度大于0,不为""
            char val[] = value;   //获得当前对象的值

            //重点,String的哈希函数

            for (int i = 0; i < value.length; i++) {  //遍历len次
                h = 31 * h + val[i];         //每次都是31 * 每次循环获得的h +第i个字符的ASSIC码
            }
            hash = h;
        }
        return h;  //由此可见""空字符对象的哈希值为0
    }
/**
    * 返回cn对应的字符在字符串中第一次出现的位置,从字符串的索引0位置开始遍历
    * 
    */
    public int indexOf(int ch) {
        return indexOf(ch, 0);
    }

    /**
     * index方法就是返回ch字符第一次在字符串中出现的位置
     * 既从fromIndex位置开始查找,从头向尾遍历,ch整数对应的字符在字符串中第一次出现的位置
     * -1代表字符串没有这个字符,整数代表字符第一次出现在字符串的位置
     */
    public int indexOf(int ch, int fromIndex) {
        final int max = value.length; //获得字符串对象的长度
        if (fromIndex < 0) {             //如果偏移量小于0,则代表偏移量为0,校正偏移量
            fromIndex = 0;
        } else if (fromIndex >= max) {   //如果偏移量大于最大长度,则返回-1,代表没有字符串没有ch对应的字符
            // Note: fromIndex might be near -1>>>1.
            return -1;
        }

        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { //emmm,这个判断,不懂
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;             //获得字符串值
            for (int i = fromIndex; i < max; i++) {      //从fromIndex位置开始向后遍历
                if (value[i] == ch) {                    //只有字符串中的某个位置的元素等于ch
                    return i;                            //返回对应的位置,函数结束,既第一次出现的位置
                }
            }
            return -1;  //如果没有出现,则返回-1
        } else {
            return indexOfSupplementary(ch, fromIndex);  //emmm,紧紧接着没看懂的地方
        }
    }


    private int indexOfSupplementary(int ch, int fromIndex) {
        if (Character.isValidCodePoint(ch)) {
            final char[] value = this.value;
            final char hi = Character.highSurrogate(ch);
            final char lo = Character.lowSurrogate(ch);
            final int max = value.length - 1;
            for (int i = fromIndex; i < max; i++) {
                if (value[i] == hi && value[i + 1] == lo) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
    * 从尾部向头部遍历,返回cn第一次出现的位置,value.length - 1就是起点 
    * 为了理解,我们可以认为是返回cn对应的字符在字符串中最后出现的位置
    *  
    * ch是字符对应的整数
    */
    public int lastIndexOf(int ch) {
        return lastIndexOf(ch, value.length - 1);
    }

    /**
    * 从尾部向头部遍历,从fromIndex开始作为起点,返回ch对应字符第一次在字符串出现的位置
    * 既从头向尾遍历,返回cn对应字符在字符串中最后出现的一次位置,fromIndex为结束点
    *
    */
    public int lastIndexOf(int ch, int fromIndex) {
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {  //之后不解释了,emmmmmmm
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            //取最小值,作用就是校正,如果fromIndex传大了,就当时len - 1
            int i = Math.min(fromIndex, value.length - 1);   
            for (; i >= 0; i--) {      //算法中是从后向前遍历,直到i<0,退出循环
                if (value[i] == ch) {  //只有有相等,返回对应的索引位置
                    return i;
                }
            }
            return -1;   //没有找到则返回-1
        } else {
            return lastIndexOfSupplementary(ch, fromIndex);
        }
    }


    private int lastIndexOfSupplementary(int ch, int fromIndex) {
        if (Character.isValidCodePoint(ch)) {
            final char[] value = this.value;
            char hi = Character.highSurrogate(ch);
            char lo = Character.lowSurrogate(ch);
            int i = Math.min(fromIndex, value.length - 2);
            for (; i >= 0; i--) {
                if (value[i] == hi && value[i + 1] == lo) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
    * 返回第一次出现的字符串的位置
    *
    */
    public int indexOf(String str) {
        return indexOf(str, 0);
    }

    /**
    *
    * 从fromIndex开始遍历,返回第一次出现str字符串的位置
    *
    */
    public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }

    /**
    * 这是一个不对外公开的静态函数
    * source就是原始字符串,sourceOffset就是原始字符串的偏移量,起始位置。
    * sourceCount就是原始字符串的长度,target就是要查找的字符串。
    * fromIndex就是从原始字符串的第fromIndex开始遍历
    *
    */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            String target, int fromIndex) {
        return indexOf(source, sourceOffset, sourceCount,
                       target.value, 0, target.value.length,
                       fromIndex);
    }

    /**
    * 同是一个不对外公开的静态函数
    * 比上更为强大。
    * 多了一个targetOffset和targetCount,既代表别查找的字符串也可以被切割
    */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        if (fromIndex >= sourceCount) {   //如果查找的起点大于当前对象的大小
            //如果目标字符串的长度为0,则代表目标字符串为"",""在任何字符串都会出现
            //配合fromIndex >= sourceCount,所以校正第一次出现在最尾部,仅仅是校正作用
            return (targetCount == 0 ? sourceCount : -1); 
        }
        if (fromIndex < 0) {  //也是校正,如果起始点小于0,则返回0
            fromIndex = 0;
        }
        if (targetCount == 0) { //如果目标字符串长度为0,代表为"",则第一次出现在遍历起始点fromIndex
            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;
    }

    /**
    * 查找字符串Str最后一次出现的位置
    */
    public int lastIndexOf(String str) {
        return lastIndexOf(str, value.length);
    }


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


    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            String target, int fromIndex) {
        return lastIndexOf(source, sourceOffset, sourceCount,
                       target.value, 0, target.value.length,
                       fromIndex);
    }


    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        /*
         * Check arguments; return immediately where possible. For
         * consistency, don't check for null str.
         */
        int rightIndex = sourceCount - targetCount;
        if (fromIndex < 0) {
            return -1;
        }
        if (fromIndex > rightIndex) {
            fromIndex = rightIndex;
        }
        /* Empty string always matches. */
        if (targetCount == 0) {
            return fromIndex;
        }

        int strLastIndex = targetOffset + targetCount - 1;
        char strLastChar = target[strLastIndex];
        int min = sourceOffset + targetCount - 1;
        int i = min + fromIndex;

    startSearchForLastChar:
        while (true) {
            while (i >= min && source[i] != strLastChar) {
                i--;
            }
            if (i < min) {
                return -1;
            }
            int j = i - 1;
            int start = j - (targetCount - 1);
            int k = strLastIndex - 1;

            while (j > start) {
                if (source[j--] != target[k--]) {
                    i--;
                    continue startSearchForLastChar;
                }
            }
            return start - sourceOffset + 1;
        }
    }
/**
    *  截取当前字符串对象的片段,组成一个新的字符串对象
    *  beginIndex为截取的初始位置,默认截到len - 1位置
    */
    public String substring(int beginIndex) {
        if (beginIndex < 0) {   //小于0抛异常
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;  //新字符串的长度
        if (subLen < 0) {       //小于0抛异常
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //如果beginIndex是0,则不用截取,返回自己(非新对象),否则截取0到subLen位置,不包括(subLen)
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }

    /**
    * 截取一个区间范围
    * [beginIndex,endIndex),不包括endIndex
    */
    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);
    }


    public CharSequence subSequence(int beginIndex, int endIndex) {
        return this.substring(beginIndex, endIndex);
    }
  /**
    * String的拼接函数
    * 例如:String  str = "abc"; str.concat("def")    output: "abcdef"
    *
    */
    public String concat(String str) {
        int otherLen = str.length();//获得参数字符串的长度
        if (otherLen == 0) { //如果长度为0,则代表不需要拼接,因为str为""
            return this;
        }

        /****重点****/

        int len = value.length;  //获得当前对象的长度 
        //将数组扩容,将value数组拷贝到buf数组中,长度为len + str.lenght
        char buf[] = Arrays.copyOf(value, len + otherLen); 
        str.getChars(buf, len); //然后将str字符串从buf字符数组的len位置开始覆盖,得到一个完整的buf字符数组
        return new String(buf, true);//构建新的String对象,调用私有的String构造方法
    }
//替换,将字符串中的oldChar字符全部替换成newChar
    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {    //如果旧字符不等于新字符的情况下
            int len = value.length;  //获得字符串长度
            int i = -1;              //flag
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {      //循环len次
                if (val[i] == oldChar) { //找到第一个旧字符,打断循环
                    break;
                }
            }
            if (i < len) {   //如果第一个旧字符的位置小于len
                char buf[] = new char[len]; 新new一个字符数组,len个长度
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];        把旧字符的前面的字符都复制到新字符数组上
                }
                while (i < len) {           //从i位置开始遍历
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c; //发生旧字符就替换,不想关的则直接复制
                    i++;
                }
                return new String(buf, true);  //通过新字符数组buf重构一个新String对象
            }
        }
        return this;  //如果old = new ,直接返回自己
    }


    //替换第一个旧字符
    String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }

    //当不是正规表达式时,与replace效果一样,都是全体换。如果字符串的正则表达式,则规矩表达式全体替换
    public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }

    //可以用旧字符串去替换新字符串
    public String replace(CharSequence target, CharSequence replacement) {
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
    }
/**
    * matches() 方法用于检测字符串是否匹配给定的正则表达式。
    * regex -- 匹配字符串的正则表达式。
    * 如:String Str = new String("www.snailmann.com");
    * System.out.println(Str.matches("(.*)snailmann(.*)"));   output:true
    * System.out.println(Str.matches("www(.*)"));             output:true
    */
    public boolean matches(String regex) {
        return Pattern.matches(regex, this);   //实际使用的是Pattern.matches()方法
    }

    //是否含有CharSequence这个子类元素,通常用于StrngBuffer,StringBuilder
    public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
    }
public String[] split(String regex, int limit) {
        /* fastpath if the regex is a
         (1)one-char String and this character is not one of the
            RegEx's meta characters ".$|()[{^?*+\\", or
         (2)two-char String and the first char is the backslash and
            the second is not the ascii digit or ascii letter.
         */
        char ch = 0;
        if (((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
              ((ch-'a')|('z'-ch)) < 0 &&
              ((ch-'A')|('Z'-ch)) < 0)) &&
            (ch < Character.MIN_HIGH_SURROGATE ||
             ch > Character.MAX_LOW_SURROGATE))
        {
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    list.add(substring(off, next));
                    off = next + 1;
                } else {    // last one
                    //assert (list.size() == limit - 1);
                    list.add(substring(off, value.length));
                    off = value.length;
                    break;
                }
            }
            // If no match was found, return this
            if (off == 0)
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));

            // Construct result
            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }



    public String[] split(String regex) {
        return split(regex, 0);
    }
/**
  * join方法是JDK1.8加入的新函数,静态方法
  * 这个方法就是跟split有些对立的函数,不过join是静态方法
  * delimiter就是分割符,后面就是要追加的可变参数,比如str1,str2,str3
  * 
  * 例子:String.join(",",new String("a"),new String("b"),new String("c"))
  * output: "a,b,c"
  */    
  public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);  //就是检测是否为Null,是null,抛异常
        Objects.requireNonNull(elements);   //不是就返回自己,即nothing happen
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);  //嗯,有兴趣自己看StringJoiner类源码啦
        for (CharSequence cs: elements) {
            joiner.add(cs);   //既用分割符delimiter将所有可变参数的字符串分割,合并成一个字符串
        }
        return joiner.toString();
    }

   /**
   * 功能是一样的,不过传入的参数不同
   * 这里第二个参数一般就是装着CharSequence子类的集合
   * 比如String.join(",",lists)   
   * list可以是一个Collection接口实现类,所含元素的基类必须是CharSequence类型
   * 比如String,StringBuilder,StringBuffer等
   */ 
   public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }
/**
    * 去除字符串首尾部分的空值,如,' ' or " ",非""
    * 原理是通过substring去实现的,首尾各一个指针
    * 头指针发现空值就++,尾指针发现空值就--
    * ' '的Int值为32,其实不仅仅是去空的作用,应该是整数值小于等于32的去除掉
    */
   public String trim() {
        int len = value.length; //代表尾指针,实际是尾指针+1的大小
        int st = 0;             //代表头指针
        char[] val = value;    /* avoid getfield opcode */

        //st<len,且字符的整数值小于32则代表有空值,st++
        while ((st < len) && (val[st] <= ' ')) {   
            st++;
        }
        //len - 1才是真正的尾指针,如果尾部元素的整数值<=32,则代表有空值,len--
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
        //截取st到len的字符串(不包括len位置)
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }
public String toString() {
        return this;
     }
/**
    * 就是将String转换为字符数组并返回
    */
     public char[] toCharArray() {
        // Cannot use Arrays.copyOf because of class initialization order issues
        char result[] = new char[value.length];     //定义一个要返回的空数组,长度为字符串长度
        System.arraycopy(value, 0, result, 0, value.length); //拷贝
        return result; //返回
     }
public String toLowerCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }

        int firstUpper;
        final int len = value.length;

        /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstUpper = 0 ; firstUpper < len; ) {
                char c = value[firstUpper];
                if ((c >= Character.MIN_HIGH_SURROGATE)
                        && (c <= Character.MAX_HIGH_SURROGATE)) {
                    int supplChar = codePointAt(firstUpper);
                    if (supplChar != Character.toLowerCase(supplChar)) {
                        break scan;
                    }
                    firstUpper += Character.charCount(supplChar);
                } else {
                    if (c != Character.toLowerCase(c)) {
                        break scan;
                    }
                    firstUpper++;
                }
            }
            return this;
        }

        char[] result = new char[len];
        int resultOffset = 0;  /* result may grow, so i+resultOffset
                                * is the write location in result */

        /* Just copy the first few lowerCase characters. */
        System.arraycopy(value, 0, result, 0, firstUpper);

        String lang = locale.getLanguage();
        boolean localeDependent =
                (lang == "tr" || lang == "az" || lang == "lt");
        char[] lowerCharArray;
        int lowerChar;
        int srcChar;
        int srcCount;
        for (int i = firstUpper; i < len; i += srcCount) {
            srcChar = (int)value[i];
            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE
                    && (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
                srcChar = codePointAt(i);
                srcCount = Character.charCount(srcChar);
            } else {
                srcCount = 1;
            }
            if (localeDependent ||
                srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
                srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
            } else {
                lowerChar = Character.toLowerCase(srcChar);
            }
            if ((lowerChar == Character.ERROR)
                    || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
                if (lowerChar == Character.ERROR) {
                    lowerCharArray =
                            ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
                } else if (srcCount == 2) {
                    resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
                    continue;
                } else {
                    lowerCharArray = Character.toChars(lowerChar);
                }

                /* Grow result if needed */
                int mapLen = lowerCharArray.length;
                if (mapLen > srcCount) {
                    char[] result2 = new char[result.length + mapLen - srcCount];
                    System.arraycopy(result, 0, result2, 0, i + resultOffset);
                    result = result2;
                }
                for (int x = 0; x < mapLen; ++x) {
                    result[i + resultOffset + x] = lowerCharArray[x];
                }
                resultOffset += (mapLen - srcCount);
            } else {
                result[i + resultOffset] = (char)lowerChar;
            }
        }
        return new String(result, 0, len + resultOffset);
    }


    public String toLowerCase() {
        return toLowerCase(Locale.getDefault());
    }


    public String toUpperCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }

        int firstLower;
        final int len = value.length;

        /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstLower = 0 ; firstLower < len; ) {
                int c = (int)value[firstLower];
                int srcCount;
                if ((c >= Character.MIN_HIGH_SURROGATE)
                        && (c <= Character.MAX_HIGH_SURROGATE)) {
                    c = codePointAt(firstLower);
                    srcCount = Character.charCount(c);
                } else {
                    srcCount = 1;
                }
                int upperCaseChar = Character.toUpperCaseEx(c);
                if ((upperCaseChar == Character.ERROR)
                        || (c != upperCaseChar)) {
                    break scan;
                }
                firstLower += srcCount;
            }
            return this;
        }

        /* result may grow, so i+resultOffset is the write location in result */
        int resultOffset = 0;
        char[] result = new char[len]; /* may grow */

        /* Just copy the first few upperCase characters. */
        System.arraycopy(value, 0, result, 0, firstLower);

        String lang = locale.getLanguage();
        boolean localeDependent =
                (lang == "tr" || lang == "az" || lang == "lt");
        char[] upperCharArray;
        int upperChar;
        int srcChar;
        int srcCount;
        for (int i = firstLower; i < len; i += srcCount) {
            srcChar = (int)value[i];
            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
                (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
                srcChar = codePointAt(i);
                srcCount = Character.charCount(srcChar);
            } else {
                srcCount = 1;
            }
            if (localeDependent) {
                upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
            } else {
                upperChar = Character.toUpperCaseEx(srcChar);
            }
            if ((upperChar == Character.ERROR)
                    || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
                if (upperChar == Character.ERROR) {
                    if (localeDependent) {
                        upperCharArray =
                                ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
                    } else {
                        upperCharArray = Character.toUpperCaseCharArray(srcChar);
                    }
                } else if (srcCount == 2) {
                    resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
                    continue;
                } else {
                    upperCharArray = Character.toChars(upperChar);
                }

                /* Grow result if needed */
                int mapLen = upperCharArray.length;
                if (mapLen > srcCount) {
                    char[] result2 = new char[result.length + mapLen - srcCount];
                    System.arraycopy(result, 0, result2, 0, i + resultOffset);
                    result = result2;
                }
                for (int x = 0; x < mapLen; ++x) {
                    result[i + resultOffset + x] = upperCharArray[x];
                }
                resultOffset += (mapLen - srcCount);
            } else {
                result[i + resultOffset] = (char)upperChar;
            }
        }
        return new String(result, 0, len + resultOffset);
    }


    public String toUpperCase() {
        return toUpperCase(Locale.getDefault());
    }
//JAVA字符串格式化
    //新字符串使用本地语言环境,制定字符串格式和参数生成格式化的新字符串。
    public static String format(String format, Object... args) {
        return new Formatter().format(format, args).toString();
    }

    //使用指定的语言环境,制定字符串格式和参数生成格式化的字符串。
    public static String format(Locale l, String format, Object... args) {
        return new Formatter(l).format(format, args).toString();
    }
//将Object转换为String

    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

    //将char数组转换为String
    public static String valueOf(char data[]) {
        return new String(data);
    }

    //将字符数组的子数组转换为String
    public static String valueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    //e...重复
    public static String copyValueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    //e...重复
    public static String copyValueOf(char data[]) {
        return new String(data);
    }

    //将布尔值转换为String
    public static String valueOf(boolean b) {
        return b ? "true" : "false";
    }

    //将单个字符转换为String
    public static String valueOf(char c) {
        char data[] = {c};
        return new String(data, true);
    }

    //将int转换为String
    public static String valueOf(int i) {
        return Integer.toString(i);
    }

    //将long转换为String
    public static String valueOf(long l) {
        return Long.toString(l);
    }

    //将float转换为String
    public static String valueOf(float f) {
        return Float.toString(f);
    }

    //将double转换为String
    public static String valueOf(double d) {
        return Double.toString(d);
    }
/**
* String类中唯一的一条本地方法,既不是用Java语言实现的方法。 
*比如str.intern(),作用就是去字符串常量池中寻找str字符串,如果有则返回str在常量池中的引用,如果没有则在常量池中创建str对象
*/
public native String intern();
  }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值