答案可能存在于某处,但我找不到。我是从我正在创建的算法中提出这个问题的。本质上是一个 .contains(String s1, String s2)
,如果 s1 包含 s2,则返回 true,忽略希腊语/英语字符差异。例如,字符串 'nai, course' 包含字符串 'ναι'。但是,这与我的问题无关。
contains()
的 String
方法使用 naive approach,我的算法也使用相同的方法。 contains()
的本质是用正确的参数调用 static
中存在的 indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)
java.lang.String.class
。
当我对我的算法进行不同类型的基准测试和测试时,我删除了所有希腊语 - 英语逻辑,以查看它仅使用英语字符串的表现有多快。而且速度更慢。大约比来自 JDK 的 s1.contains(s2)
慢 2 倍。
因此,我花时间将这个 indexOf
方法复制并粘贴到我的类中,并以 JDK 为字符串调用它的相同方式调用了 1500 万次。
类如下:
public class TestIndex {
public static int fromJdk;
public static int fromMe;
public static void main(String[] args) {
String s1 = "papapatita";
String s2 = "patita";
final char[] s1Arr = s1.toCharArray();
int s1Length = s1Arr.length;
final char[] s2Arr = s2.toCharArray();
int s2Length = s2Arr.length;
long be4 = System.nanoTime();
for (int i = 0; i < 15_000_000; i++) {
fromJdk = s1.indexOf(s2);
// fromMe = indexOf(s1Arr, 0, s1Length, s2Arr, 0, s2Length, 0);
}
long after = System.nanoTime();
System.out.println((after - be4) / 1000000.0);
}
static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset,
int targetCount, int fromIndex) {
if (fromIndex >= sourceCount) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {
while (++i <= max && source[i] != first)
;
}
/* Found first character, now look at the rest of v2 */
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) {
/* Found whole string. */
return i - sourceOffset;
}
}
}
return -1;
}
}
虽然 fromJdk = s1.indexOf(s2);
没有注释,但结果是(在我的机器上)大约 150 毫秒。如果我对此行进行注释并保留 fromMe = indexOf(s1Arr, 0, s1Length, s2Arr, 0, s2Length, 0);
不加注释,我应该得到相同的结果。结果几乎是两倍。大约 300 毫秒。
那么,问题是为什么? indexOf
方法与它在 JDK 中的存在完全一样。我知道在 Java 中测量性能是一件很难的事情(可能是 JMH)?但是差别很大。来自 JDK 的 indexOf
是否在幕后得到特殊处理?
如果某处有答案,请指点我。
答案 0 :(得分:4)
因为 String.indexOf()
是一个 intrinsic method,所以 JDK 调用的是本机实现,而您的调用是 Java 实现。
JVM 实际上并不执行您看到的 Java 代码,它知道可以用更高效的版本替换它。当您复制代码时,它会通过常规的 JIT 编译,从而降低效率。只是 JVM 为提高性能所做的 dozens of tricks 之一,开发人员通常甚至没有意识到。