前言

本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和文献引用请见100个问题搞定Java虚拟机

正文

在 Java 9 之前,字符串是用 char 数组来存储的,主要为了支持非英文字符。

然而,大多数 Java 程序中的字符串都是由 Latin1 字符组成的。

也就是说每个字符仅需占据一个字节,而使用 char 数组的存储方式将极大地浪费内存空间。

Java 9 引入了 Compact Strings 的概念,当字符串仅包含 Latin1 字符时,使用一个字节代表一个字符的编码格式,使得内存使用效率大大提高

String#indexof 底层部分源码解析(JDK 11.0.11)

实际上 JDK9~JDK11 这部分源码未发生过变动,不过 JDK11 为 LTS 版本,我推荐使用 JDK11 来分析

/**
 * 在字符串 value 中查找字符串 str,注意 str 和 value 都是由 Latin1 字符构成,故底层都是用字节数组存储数据
 * @param value 原始字符串
 * @param str 待查找的字符串
 * @return 返回 value 中出现 str 的第一个索引值,返回 -1 说明找不到
 */
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, byte[] str) {
    // str 为空,则返回 0
    if (str.length == 0) {
        return 0;
    }
    // value 为空,返回 -1
    if (value.length == 0) {
        return -1;
    }
    return indexOf(value, value.length, str, str.length, 0);
}

/**
 * 在字符串 value 中查找字符串 str,注意 str 和 value 都是由 Latin1 字符构成,故底层都是用字节数组存储数据
 * @param value 原始字符串
 * @param valueCount 要查找的原始字符串数量 
 * @param str 待查找的字符串
 * @param strCount 待查找的字符串数量
 * @param fromIndex 从原始字符串的哪个索引值开始查找        
 * @return 返回 value 中出现 str 的第一个索引值,返回 -1 说明找不到
 */
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
    // 原始字符串的第一个字符
    byte first = str[0];
    int max = (valueCount - strCount);
    for (int i = fromIndex; i <= max; i++) {
        // 查找第一个字符
        if (value[i] != first) {
            while (++i <= max && value[i] != first);
        }
        if (i <= max) {
            // 这时候 i 代表 value 里面出现 str 第一个字符 所在的索引值
            int j = i + 1;
            // j 最多遍历到的索引值
            int end = j + strCount - 1;
            // j 一遍遍往右挪,如果挪到了 end 说明找到了目标字符串
            for (int k = 1; j < end && value[j] == str[k]; j++, k++);
            if (j == end) {
                // 找到了 str
                return i;
            }
        }
    }
    return -1;
}

关于 @HotSpotIntrinsicCandidate 可以参考我的这篇博客——HotSpot虚拟机中的intrinsic是指什么?

上一篇 下一篇