java源码解析之String类

Posted GolLong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java源码解析之String类相关的知识,希望对你有一定的参考价值。

上一节主要介绍了String类的一些构造方法,主要分为四类

  • 无参构造器:String(),创建一个空字符串"",区别于null字符串,""已经初始化,null并未初始化
  • 副本构造器:String(String s),简单的赋值,得到的是一个副本,俩个引用指向的是常量池中的同一个String,但是String是不可变的,所有用意不大
  • byte类构造器:String(byte[] b),将byte数组转换为String,注意并不是简单的赋值,而是整体copy一份
  • char类构造器:String(char[] c),将char数组转换成String,注意并不是简单的赋值,而是整体copy一份
  • codepoints构构器:String(int[] i),将超过char表示范围的字符转换为为String
  • String缓存流的转换:String(StringBuffer),将字符换缓冲流转换为String
    /*
     * 获得字符串的长度,也就是属性value数组的长度
     */
    public int length() {
        return value.length;
    }

    /*
     * 判断字符串是否为空,也就是判断属性value数组的长度是否等于0
     */
    public boolean isEmpty() {
        return value.length == 0;
    }

    /*
     * charAt方法可以直接获取当前下标对应的字符,这对于判断某个位置的字符值很方便
     * 区别于
     */
    public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

    /*
     * 返回指定索引处的字符(Unicode代码点)。 codePoint在上一章已经介绍过了,具体就是那些超出byte和char表示方位的字符
     */
    public int codePointAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointAtImpl(value, index, value.length);
    }

    /*
     * 返回指定索引之前的字符(Unicode代码点)。
     */
    public int codePointBefore(int index) {
        int i = index - 1;
        if ((i < 0) || (i >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointBeforeImpl(value, index, 0);
    }

    /*
     * 返回此 String指定文本范围内的Unicode代码点数。 
     */
    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);
    }

    /*
     * 返回此String中的索引,该索引通过codePointOffset代码点从给定的index偏移。
     * index和codePointOffset给出的文本范围内的未配对代理计为每个代码点。
     *
     */
    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);
    }

    /*
     * 将此字符串复制给dst字节数组,默认为整体复制,其中dstBegin为目标数组dst中的开始位置
     * 此方法为包访问权限,所以我们并没有调用的权限
     */
    void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }

    /*
     * 将此字符串的额指定位置开始到指定位置结束复制给dst字节数组,其中dstBegin为目标数组dst的开始位置,
     * srcBegin和srcEnd分别为本字符串的开始位置和结束位置
     */
    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);
    }

    /*
     * 方法已过时
     * 使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中,可以指定字符串的开始位置和结束位置,
     * 但结果往往是不正确的,在源码中我们可以看到,仅仅是将字符串的每一位字符强转成字节类型,实际用处很少。
     * 
     */
    @Deprecated
    public void getBytes(int srcBegin, int srcEnd, byte 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);
        }
        Objects.requireNonNull(dst);

        int j = dstBegin;
        int n = srcEnd;
        int i = srcBegin;
        char[] val = value; /* avoid getfield opcode */

        while (i < n) {
            dst[j++] = (byte) val[i++];
        }
    }

    /*
     * 指定编码字符集将此 String编码为字节序列,将结果存储到新的字节数组中
     */
    public byte[] getBytes(String charsetName) throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException();
        return StringCoding.encode(charsetName, value, 0, value.length);
    }

    /*
     * 指定编码字符集将此 String编码为字节序列,将结果存储到新的字节数组中
     */
    public byte[] getBytes(Charset charset) {
        if (charset == null)
            throw new NullPointerException();
        return StringCoding.encode(charset, value, 0, value.length);
    }

    /*
     * 使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中
     */
    public byte[] getBytes() {
        return StringCoding.encode(value, 0, value.length);
    }

    /*
     * String重写Object类的equals方法,详细阅读源码,我们发现形参是Object类型,那么在实际传参的过程当中
     * 除了String类型,别的引用类型都会返回false,重点注意的是StringBuffer和StringBuild,在实际比较的时候一定要先进行转换
     * equals实际比较的就是字符串的每一位依次进行比较,直到全部比较完毕都没有不一样的才返回true
     */
    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;
    }

    /*
     * 将此字符串与指定的StringBuffer进行 比较内容是否相等
     */
    public boolean contentEquals(StringBuffer sb) {
        return contentEquals((CharSequence) sb);
    }

    private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
        char v1[] = value;
        char v2[] = sb.getValue();
        int n = v1.length;
        if (n != sb.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != v2[i]) {
                return false;
            }
        }
        return true;
    }

    /*
     * 将此字符串与指定的CharSequence进行内容比较是否相等
     */
    public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            if (cs instanceof StringBuffer) {
                synchronized (cs) {
                    return nonSyncContentEquals((AbstractStringBuilder) cs);
                }
            } else {
                return nonSyncContentEquals((AbstractStringBuilder) cs);
            }
        }
        // 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;
    }

    /*
     * 能用一行代价解决的事就不用俩行,三元运算符?:直接解决。其中regionMatches(true, 0, anotherString, 0, value.length)是测试是否相等的函数
     * 第一个参数true代表忽略大小写
     */
    public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null) && (anotherString.value.length == value.length)
                        && regionMatches(true, 0, anotherString, 0, value.length);
    }

 

以上是关于java源码解析之String类的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码解析之基础应用

Java String源码解析

Java String源码解析

jdk源码解析--String 类

JDK源码解析之Java的SPI机制

Java基础1----Object类解析