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+)相同有道理。谢谢。有道理。谢谢。