String源码笔记

  • equals(Object anObject)
    重写的equals方法,不再比较内存地址而是比较字符串是否相同。
/**
     * 比较流程:
     * 1.先比较对象是否相等,相等直接返回true
     * 2.比较类型
     * 3.比较长度
     * 4.从第一个字符比到最后一个字符
     */
    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;
    }




  • 各种重载的valueOf()方法:
  1. 对于Object,调用Object的toString()
  2. 对于char和char[],返回一个新的String。
  3. 对于各种数字包装类,调用包装类中带参数的的toString(int i)(以int举例)。
  public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
  }

  public static String valueOf(char data[]) {
    return new String(data);
  }

  public static String valueOf(boolean b) {
    return b ? "true" : "false";
  }

  public static String valueOf(char c) {
    char data[] = {c};
    return new String(data, true);
  }

  public static String valueOf(int i) {
    return Integer.toString(i);
  }

  public static String valueOf(long l) {
    return Long.toString(l);
  }

  public static String valueOf(float f) {
    return Float.toString(f);
  }

  public static String valueOf(double d) {
    return Double.toString(d);
  }




  • indexOf()
    各种重载indexOf()调用的底层indexOf()方法:
/**
     * 在source字符串里面搜target字符串,判断source是否包含target字符串。
     * 由于对数据结构不够熟悉,且应用时基本偏移量都时0,所以将这段源码中的偏移量offset默认为0
     *
     * @param source       被搜字符串的字符数组
     * @param sourceOffset source偏移量(一般都是0)
     * @param sourceCount  source字符数组的长度
     * @param target       目标字符串的字符数组
     * @param targetOffset target的偏移量(一般都是0)
     * @param targetCount  target字符数组的长度
     * @param fromIndex    从fromIndex索引开始搜索
     * @return 正确时返回target字符串在source字符串中的fromIndex索引起第一次出现的下标,找不到、逻辑错误等都返回-1
     */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
                       char[] target, int targetOffset, int targetCount,
                       int fromIndex) {
        if (fromIndex >= sourceCount) {
            //索引超出source字符串长度时,target字符串如果不是 "" 就返回-1
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        //如果目标字符串为"",直接返回fromIndex
        if (targetCount == 0) {
            return fromIndex;
        }

        //target字符串的第一个字符
        char first = target[targetOffset];
        //搜索的最大长度。
        //从source的fromIndex开始到max结束,先比对首字符,如果首字符相同就从第二个字符开始比对到最后一个字符。如果比对失败返回-1
        int max = sourceOffset + (sourceCount - targetCount);
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            //比对首字符,比对到当i和max相等时结束
            //比对不到就一直在while循环中
            if (source[i] != first) {
                while (++i <= max && source[i] != first) ;
            }

            //比对source和target数组中第二个字符起的剩余字符
            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) {
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }




  • lastIndexOf()
    各种重载lastIndexOf()调用的底层lastIndexOf()方法:
    /**
     * 在源字符串中从fromIndex起从右往左搜索,返回目标字符串第一次出现的下标。
     * 参数和indexOf()方法中的参数相似。
     */
    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;
        }
        //空字符串必定匹配
        if (targetCount == 0) {
            return fromIndex;
        }

        //目标字符串末尾字符的下标
        int strLastIndex = targetOffset + targetCount - 1;
        //目标字符串末尾字符
        char strLastChar = target[strLastIndex];
        //当源字符串下标从0开始,目标字符串出现在源字符串最左边时的下标
        int min = sourceOffset + targetCount - 1;
        //目标字符串出现在fromIndex最右边的下标
        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;
        }
    }




  • substring(int beginIndex, int endIndex):按下标截取字符串
/**
     * 传入开始和结束的下标,截取这段字符串并作为新的String返回
     *
     * @param beginIndex 开始的下标,闭区间(包含)
     * @param endIndex   结束的下标,开区间(不包含)
     * @return 返回截取的字符串
     * @throws IndexOutOfBoundsException
     * 抛异常情况:1.beginIndex为负;2.endIndex超出字符串总长度;3.beginIndex大于endIndex;
     */
    public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        //因为endIndex是开区间,所以endIndex等于字符串长度时才包含最后一个字符
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //beginIndex从0开始且endIndex为String长度时返回本身,否则调用构造函数
        return ((beginIndex == 0) && (endIndex == value.length)) ?this
                : new String(value, beginIndex, subLen);
    }




  • concat(String str):将传入String连接到源String的末尾,并返回新的一个String。
    底层调用了System类中的arraycopy(Object src, int srcPos, Object dest, int destPos, int length)方法。
    这个方法是从src中srcPos下标开始,复制长度为length的数据到数组dest的destPos之后,此下标后的内容会被覆盖。
/**
     * @param str 传入的字符串
     * @return 返回的字符串,可能是本身或者新字符串
     */
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        //拿到自身的长度
        int len = value.length;
        //用创建一个新的char数组方式扩容,用来接收str的字符
        char buf[] = Arrays.copyOf(value, len + otherLen);
        //将str的字符连接到末尾
        str.getChars(buf, len);
        return new String(buf, true);
    }




  • replace(char oldChar, char newChar):替换字符
    /**
     * 字符串替换方法,将字符串中的所有oldChar替换成newChar
     * 如果字符串中不包含oldChar就返回本身
     *
     * @param oldChar 被替换的字符
     * @param newChar 新字符
     * @return 返回一个新String
     */
    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value;

            //i为oldChar第一次出现的下标
            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            //如果while有没有找到oldChar,不进入这个if
            if (i < len) {
                char buf[] = new char[len];
                //复制下标i之前的内容
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                //复制i及之后的内容,并将所有oldChar替换成newChar
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

你可能感兴趣的:(String源码笔记)