加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

String 部分源码分析

发布时间:2020-12-14 06:13:00 所属栏目:百科 来源:网络整理
导读:String 无参数构造函数 /** * 底层存储字符串的目标字节数组, * Jdk 8 之前都是字符数组 private final char[] value; */ @Stable private final byte[] value; /** * 编码底层字节数组的字符集,支持 LATIN1、UTF16 */ private final byte coder; /** * 字

String

  • 无参数构造函数
/**
     * 底层存储字符串的目标字节数组,
     * Jdk 8 之前都是字符数组 private final char[] value;
     */
    @Stable
    private final byte[] value;
    /**
     * 编码底层字节数组的字符集,支持 LATIN1、UTF16
     */
    private final byte coder;
    /**
     * 字符串的哈希码值,默认为 0
     */
    private int hash; // Default to 0

    /**
     * 创建一个空字符串
     * created by ZXD at 18 Nov 2018 T 11:17:48
     */
    public String() {
        this.value = "".value;
        this.coder = "".coder;
    }
  • 基于字节数组创建字符串
public String(byte[] bytes) {
        this(bytes,bytes.length);
    }

    public String(byte bytes[],int offset,int length) {
        checkBoundsOffCount(offset,length,bytes.length);
        // 对目标字节数组进行编码    
        StringCoding.Result ret = StringCoding.decode(bytes,offset,length);
        // 获取编码后的字节数组
        this.value = ret.value;
        // 获取编码后的字符集
        this.coder = ret.coder;
    }

    public String(byte bytes[],Charset charset) {
        this(bytes,bytes.length,charset);
    }
    
    public String(byte bytes[],int length,Charset charset) {
        // 防御式编程,null 校验
        if (charset == null)
            throw new NullPointerException("charset");
        checkBoundsOffCount(offset,bytes.length);
        // 根据指定的字符集对字节数组进行编码
        StringCoding.Result ret =
            StringCoding.decode(charset,bytes,length);
        this.value = ret.value;
        this.coder = ret.coder;
    }

    public String(byte bytes[],String charsetName)
            throws UnsupportedEncodingException {
        this(bytes,charsetName);
    }

    public String(byte bytes[],String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        checkBoundsOffCount(offset,bytes.length);
        // 根据指定的字符集对字节数组进行编码,编码名称错误时,抛出 UnsupportedEncodingException 异常
        StringCoding.Result ret =
            StringCoding.decode(charsetName,length);
        this.value = ret.value;
        this.coder = ret.coder;
    }
  • 基于字符数组创建字符串
public String(char value[]) {
        this(value,value.length,null);
    }

    public String(char value[],int count) {
        this(value,count,rangeCheck(value,count));
    }

    private static Void rangeCheck(char[] value,int count) {
        // 字符串下标合法性校验
        checkBoundsOffCount(offset,value.length);
        return null;
    }

    String(char[] value,int off,int len,Void sig) {
        // 特殊场景优化处理
        if (len == 0) {
            this.value = "".value;
            this.coder = "".coder;
            return;
        }
        if (COMPACT_STRINGS) {
            // 如果启用压缩,则将字符数组压缩,字符集设置为 LATIN1
            byte[] val = StringUTF16.compress(value,off,len);
            if (val != null) {
                this.value = val;
                this.coder = LATIN1;
                return;
            }
        }
        // 字符数组不压缩时,字符集设置为 UTF16
        this.coder = UTF16;
        this.value = StringUTF16.toBytes(value,len);
    }
  • 字符串内容相等性比较
public boolean equals(Object anObject) {
        // 地址相等则直接返回 true
        if (this == anObject) {
            return true;
        }
        // 形参对象为字符串
        if (anObject instanceof String) {
            String aString = (String)anObject;
            // 字符编码相同时才能做比较
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value,aString.value)
                                  : StringUTF16.equals(value,aString.value);
            }
        }
        return false;
    }
  • 字符串的长度
public int length() {
        return value.length >> coder();
    }

    byte coder() {
        return COMPACT_STRINGS ? coder : UTF16;
    }

    @Native static final byte LATIN1 = 0;
    @Native static final byte UTF16  = 1; // Unicode字符集的抽象码位映射为16位长的整数
  • 比较字符串内容并且不区分大小写
public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null) // 形参字符串不为 null
                && (anotherString.length() == length()) // 两个字符串长度一致
                && regionMatches(true,anotherString,length()); // 编码后的区域是否匹配
    }
  • 字符串拼接
public String concat(String str) {
        int olen = str.length();
        if (olen == 0) {
            return this;
        }

        // 字符集相同时,直接通过数组拷贝进行拼接
        if (coder() == str.coder()) {
            byte[] val = this.value;
            byte[] oval = str.value;
            int len = val.length + oval.length;
            byte[] buf = Arrays.copyOf(val,len);
            System.arraycopy(oval,buf,val.length,oval.length);
            return new String(buf,coder);
        }
        int len = length();
        // 使用 UTF16 编码计算目标字节数组长度,并将它们都拷贝进去。
        byte[] buf = StringUTF16.newBytesFor(len + olen);
        getBytes(buf,UTF16);
        str.getBytes(buf,len,UTF16);
        return new String(buf,UTF16);
    }
  • 字符串截取
public String substring(int beginIndex,int endIndex) {
        int length = length();
        // 索引合法性检测
        checkBoundsBeginEnd(beginIndex,endIndex,length);
        int subLen = endIndex - beginIndex;
        // 特殊场景优化处理,截取的子字符串就是目标字符串
        if (beginIndex == 0 && endIndex == length) {
            return this;
        }
        return isLatin1() ? StringLatin1.newString(value,beginIndex,subLen)
                          : StringUTF16.newString(value,subLen);
    }
    
    /**
     * 起始索引和结束索引不在 0到 length()-1 范围内,则抛出 IndexOutOfBoundsException 异常
     * 结束索引大于起始索引,则抛出 IndexOutOfBoundsException 异常
     */ 
    static void checkBoundsBeginEnd(int begin,int end,int length) {
        if (begin < 0 || begin > end || end > length) {
            throw new StringIndexOutOfBoundsException(
                "begin " + begin + ",end " + end + ",length " + length);
        }
    }
  • 获取字符串中指定索引处的单个字符
public char charAt(int index) {
        if (isLatin1()) {
            return StringLatin1.charAt(value,index);
        } else {
            return StringUTF16.charAt(value,index);
        }
    }

    StringLatin1#charAt
    public static char charAt(byte[] value,int index) {
        if (index < 0 || index >= value.length) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return (char)(value[index] & 0xff);
    }
  • 目标字符串是否包含子字符串
public boolean contains(CharSequence s) {
        return indexOf(s.toString()) >= 0;
    }
  • 字符串是否为空
public boolean isEmpty() {
        return value.length == 0;
    }
  • 字符串替换
public String replace(char oldChar,char newChar) {
        if (oldChar != newChar) {
            String ret = isLatin1() ? StringLatin1.replace(value,oldChar,newChar)
                                    : StringUTF16.replace(value,newChar);
            if (ret != null) {
                return ret;
            }
        }
        return this;
    }

    public String replace(CharSequence target,CharSequence replacement) {
        // 需要查找的字符序列
        String tgtStr = target.toString();
        // 需要替换的字符序列
        String replStr = replacement.toString();
        // 如果要查找的字符序列没有在目标字符串中,则返回其本身
        int j = indexOf(tgtStr);
        if (j < 0) {
            return this;
        }
        // 查找字符序列的长度
        int tgtLen = tgtStr.length();
        int tgtLen1 = Math.max(tgtLen,1);
        // 当期字符串的长度
        int thisLen = length();

        int newLenHint = thisLen - tgtLen + replStr.length();
        if (newLenHint < 0) {
            throw new OutOfMemoryError();
        }
        StringBuilder sb = new StringBuilder(newLenHint);
        int i = 0;
        // 在 StringBuilder 指定的索引处追加字符串,并重新获取要查找的子字符串索引进行循环替换。
        do {
            sb.append(this,i,j).append(replStr);
            i = j + tgtLen;
        } while (j < thisLen && (j = indexOf(tgtStr,j + tgtLen1)) > 0);
        return sb.append(this,thisLen).toString();
    }
  • 基于正则表达式替换字符串
public String replaceAll(String regex,String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }
  • 基于正则表达式替换首次出现的字符串
public String replaceFirst(String regex,String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读