前言
本文隶属于专栏《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是指什么?