Java String#indexOf:为什么用JDK代码比较1500万个字符串要比我的代码快?
答案可能在某处,但我找不到。我是从我正在创建的一个算法中得出这个问题的。本质上是一个Java String#indexOf:为什么用JDK代码比较1500万个字符串要比我的代码快?,java,jvm,Java,Jvm,答案可能在某处,但我找不到。我是从我正在创建的一个算法中得出这个问题的。本质上是一个.contains(字符串s1,字符串s2),如果s1包含s2,则返回true,忽略希腊/英语字符的差异。例如,字符串“nai,当然”包含字符串“ναι”。然而,这与我的问题毫不相干 字符串的contains()方法使用,我的算法使用相同的方法。contains()的基本功能是使用正确的参数调用java.lang.String.class中存在的静态索引of(char[]source,int sourceOffs
.contains(字符串s1,字符串s2)
,如果s1包含s2,则返回true,忽略希腊/英语字符的差异。例如,字符串“nai,当然”包含字符串“ναι”。然而,这与我的问题毫不相干
字符串的contains()
方法使用,我的算法使用相同的方法。contains()
的基本功能是使用正确的参数调用java.lang.String.class
中存在的静态索引of(char[]source,int sourceOffset,int sourceCount,char[]target,int targetOffset,int targetCount,int fromIndex)
当我对我的算法进行不同类型的基准测试和测试时,我删除了所有希腊-英语逻辑,以查看它在仅使用英语字符串时的运行速度。而且速度较慢。大约比来自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;
}
}
公共类测试索引{
来自jdk的公共静态int;
公共静态int fromMe;
公共静态void main(字符串[]args){
字符串s1=“papapatita”;
字符串s2=“patita”;
最终字符[]s1Arr=s1.toCharArray();
int s1Length=s1Arr.length;
最终字符[]s2Arr=s2.toCharArray();
int s2Length=s2Arr.length;
long be4=System.nanoTime();
对于(int i=0;i<15_000;i++){
fromJdk=s1.indexOf(s2);
//fromMe=索引of(s1Arr,0,s1Length,s2Arr,0,s2Length,0);
}
long after=System.nanoTime();
System.out.println((在-be4之后)/1000000.0);
}
静态int indexOf(char[]源、int sourceOffset、int sourceCount、char[]目标、int targetOffset、,
int targetCount,int fromIndex){
if(fromIndex>=sourceCount){
返回(targetCount==0?sourceCount:-1);
}
如果(从索引<0){
fromIndex=0;
}
如果(targetCount==0){
从索引返回;
}
char first=目标[targetOffset];
int max=sourceOffset+(sourceCount-targetCount);
for(int i=sourceOffset+fromIndex;i,因为String.indexOf()
是一个,使JDK调用成为本机实现,而您的调用成为Java实现
JVM实际上并没有执行您看到的Java代码,它知道它可以用一个更高效的版本来代替它。当您复制代码时,它会经过常规的JIT编译,使其效率更低。JVM只做了一件事来提高性能,开发人员甚至都没有意识到。因为String。indexOf()是一个函数,使JDK调用成为本机实现,而您的调用成为Java实现
JVM实际上并没有执行您看到的Java代码,它知道它可以用一个效率更高的版本来代替它。当您复制代码时,它会经过常规的JIT编译,从而降低效率。JVM只是为了提高性能而做的其中一件事,开发人员甚至都并没有意识到。哪个Java版本是y你在用什么?这能回答你的问题吗?@geogez。Kayaman回答了什么,如果你看一下Java11(最新LTS版本)的源代码,我会补充一下,您可以看到一个名为@hospotintrinsiccandidate
的注释,该注释指示JVM可能会用更高效的机器代码替换该方法。我可以想象这种行为在Java 8中出现过,而且很可能在那之前也出现过。@MAnouti听到这个消息也很高兴。谢谢您提供的信息。我会记住它。问题与您使用的是Java版本吗?这回答了您的问题吗?@geogez。Kayaman回答了什么,如果您查看Java 11(最新LTS版本)的源代码,我会补充一下,您可以看到一个名为@hospotintrinsicandidate
的注释,该注释指示JVM可能会用更高效的机器代码替换该方法。我可以想象这种行为在Java 8中出现过,而且很可能在那之前也出现过。@MAnouti听到这个消息也很高兴。谢谢您提供的信息。我会记住它。问题与(1+)相同有道理。谢谢。有道理。谢谢。