jdk8源码学习之String

String类

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence{}

一旦一个String对象被创建,包含在这个对象中的字符序列是不可改变的,包括该类后续的所有方法都是不能修改该对象的,直至该对象被销毁,这是我们需要特别注意的(该类的一些方法看似改变了字符串,其实内部都是创建一个新的字符串)

成员变量

/**用来存储字符串  */
private final char value[];
			
/** 缓存字符串的哈希码 */
private int hash; // Default to 0
			
/** 实现序列化的标识 */
private static final long serialVersionUID = -6849794470754667710L;
一个 String 字符串实际上是一个 char 数组。

构造方法

String str1 = "abc";
String str2 = new String("abc");
String str3 = new String(new char[]{'a','b','c'});

equals()

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;
    }

String 类重写了equals方法,比较的是组成字符串的每一个字符是否相同,如果都相同则返回true,否则返回false

hashCode()

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

这里有一个奇怪的数字31,网上查了一下,有以下两点原因:

第一,31是一个不大不小的质数,是作为hashCode乘子的优选质数之一。另外一下相近的质数,比如37、41、43等等,也都是不错的选择,那么为啥偏偏选中了31呢,请看第二个原因。

第二,31可以被JVM优化,31 * i = (i<<5) - i.。

charAt()

    public char charAt(int index) {
        // 如果传入的索引大于字符串的长度或者小于0,直接抛出索引越界异常
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

 通过传入的索引(数组下标),返回指定索引的单个字符。

compareTo()

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;
    }

按字母顺序比较两个字符串,是基于字符串中每个字符的Unicode值。当两个字符串某个位置的字符不同时,返回的是这一位置的字符Unicode值之差,当两个字符串相同时,返回两个字符串长度之差。

compareToIgnoreCase() 方法在 compareTo 方法的基础上忽略大小写,我们知道大写字母是比小写字母的Unicode值小32的,底层实现是先都转换成大写比较,然后都转换成小写进行比较。

concat()

public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

首先判断要拼接的字符串长度是否为0,如果为0,则直接返回原字符串。如果部位0,则通过Arrays工具类(后面会详细介绍这个工具类)的copyOf方法创建一个新的字符数组,长度为原字符串之和,情面填充原字符串,后面为空。接着在通过getChars方法将要拼接的字符串放入新字符串后面为空的位置。

indexOf(int ch, int fromIndex)

public int indexOf(int ch, int fromIndex) {
        final int max = value.length; // max等于字符的长度
        if (fromIndex < 0) { // 指定索引的位置如果小于0,默认从0开始搜索
            fromIndex = 0;
        } else if (fromIndex >= max) {
            // Note: fromIndex might be near -1>>>1.
            // 如果指定索引值大于等于字符的长度(因为是数组,下标最多只能是max-1),直接返回-1
            return -1;
        }

        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // 一个char占用两个字节,如果ch小于2的16次方(65536),绝大多数字符都在此范围内
            // 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++) { // for循环依次判断字符串每个字符是否和指定字符相等
                if (value[i] == ch) {
                    return i; // 存在相等的字符,返回第一次出现该字符的索引位置,并终止循环
                }
            }
            return -1; //不存在相等的字符,返回-1
        } else { // 当字符大于65536时,处理的少数情况,该方法会首先判断是否是有效字符,然后依次进行比较
            return indexOfSupplementary(ch, fromIndex);
        }
    }

indexOf(int ch),参数 ch 其实是字符的 Unicode 值,这里也可以放单个字符(默认转成int),作用是返回指定字符第一次出现的此字符串中的索引。其内部是调用 indexOf(int ch, int fromIndex),只不过这里的 fromIndex =0 ,因为是从 0 开始搜索;而 indexOf(int ch, int fromIndex) 作用也是返回首次出现的此字符串内的索引,但是从指定索引处开始搜索。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章