zoukankan      html  css  js  c++  java
  • String 部分源码分析

    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, 0, 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, 0, bytes.length, charset);
        }
        
        public String(byte bytes[], int offset, int length, Charset charset) {
            // 防御式编程,null 校验
            if (charset == null)
                throw new NullPointerException("charset");
            checkBoundsOffCount(offset, length, bytes.length);
            // 根据指定的字符集对字节数组进行编码
            StringCoding.Result ret =
                StringCoding.decode(charset, bytes, offset, length);
            this.value = ret.value;
            this.coder = ret.coder;
        }
    
        public String(byte bytes[], String charsetName)
                throws UnsupportedEncodingException {
            this(bytes, 0, bytes.length, charsetName);
        }
    
        public String(byte bytes[], int offset, int length, String charsetName)
                throws UnsupportedEncodingException {
            if (charsetName == null)
                throw new NullPointerException("charsetName");
            checkBoundsOffCount(offset, length, bytes.length);
            // 根据指定的字符集对字节数组进行编码,编码名称错误时,抛出 UnsupportedEncodingException 异常
            StringCoding.Result ret =
                StringCoding.decode(charsetName, bytes, offset, length);
            this.value = ret.value;
            this.coder = ret.coder;
        }
    
    • 基于字符数组创建字符串
        public String(char value[]) {
            this(value, 0, value.length, null);
        }
    
        public String(char value[], int offset, int count) {
            this(value, offset, count, rangeCheck(value, offset, count));
        }
    
        private static Void rangeCheck(char[] value, int offset, int count) {
            // 字符串下标合法性校验
            checkBoundsOffCount(offset, count, 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, off, 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, 0, anotherString, 0, 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, 0, buf, val.length, oval.length);
                return new String(buf, coder);
            }
            int len = length();
            // 使用 UTF16 编码计算目标字节数组长度,并将它们都拷贝进去。
            byte[] buf = StringUTF16.newBytesFor(len + olen);
            getBytes(buf, 0, 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, beginIndex, 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, oldChar, 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, i, 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);
        }
    
  • 相关阅读:
    css半透明边框
    css脱离文档流
    margin负值的作用
    浅谈BFC
    css多列布局
    css布局--水平垂直居中
    css布局--垂直居中
    css布局--水平居中
    题解-APIO2019奇怪装置
    题解-AtCoder ARC-078F Mole and Abandoned Mine
  • 原文地址:https://www.cnblogs.com/zhuxudong/p/9977719.html
Copyright © 2011-2022 走看看