19

私のアプリケーションobj.getClass().isArray()では非常に頻繁に呼び出され、アプリのボトルネックになっています。
オブジェクトが配列かどうかを実行時に効率的にチェックしたい。プリミティブ配列とオブジェクト配列は true を返す必要があります。
私が想像できる方法は、instanceofすべてのプリミティブ配列に対するものですが、int[][] のような型を処理することはできません。アプリはlibとして使用されるため、すべてのタイプをリストすることはできません.
その手がかりはありますか?

4

3 に答える 3

8

私が行ったばかりのベンチマークでは、次の結果が得られました。

{s instanceof Object[]} spends 44ms
{s.getClass().getName().charAt(0) == '['} spends 58ms
{s.getClass().isArray()} spends 303ms

ベンチマークは、 Main.javaで呼び出されるBenchmark.javaを使用して行われました。


final上記のベンチマークで変数の使用について説明した後、ローカル変数を使用して新しい結果を確認してください。

{s instanceof Object[]} spends 83ms
{s.getClass().getName().charAt(0) == '['} spends 93ms
{s.getClass().isArray()} spends 354ms

デュレーションがすべて少し長くなったとしても (興味深いことに)、それらの順序は維持されています。

Benchmark.java は、この新しいMain.javaで呼び出されています。


そして、この他のMain.javaで呼び出されるプリミティブ配列を使用します。

{a instanceof int[]} spends 71ms
{a.getClass().getName().charAt(0) == '['} spends 82ms
{a.getClass().isArray()} spends 340ms

それでも同じ結果順です。

于 2013-04-23T13:57:14.673 に答える
2

あなたのコメントから、プロファイリング結果を調査する際に解釈上の誤りに苦しんでいる可能性があると結論付けました。プロファイラーのメソッド レベルのインスツルメンテーションは、式に感銘を受けずに、非常に不自由getClass()で呼び出しが多い可能性があります。言い換えれば、おそらくここで、プロファイラーの測定オーバ​​ーヘッドを測定しているのでしょう。isArray()instanceof

その上、簡単なベンチマークでは、私はあなたの主張を支持することはできません. 次の非常にばかげたテストを実行しました。

public class Test {
    public static void main(String[] args) {
        final int rep = 10000000;
        Object[] o = {
            null,
            1,
            "x",
            new Object[0],
            new Object[0][],
            new int[0],
            new int[0][]
        };

        // "Warmup" to avoid potential JVM startup overhead
        long x = 0;
        for (int i = 0; i < rep; i++) {
            x+=checkInstanceOf(o);
        }

        for (int i = 0; i < rep; i++) {
            x+=checkIsArray(o);
        }

        for (int i = 0; i < rep; i++) {
            x+=checkClassName(o);
        }

        // Actual test
        long t1 = System.nanoTime();
        for (int i = 0; i < rep; i++) {
            x+=checkInstanceOf(o);
        }

        long t2 = System.nanoTime();
        for (int i = 0; i < rep; i++) {
            x+=checkIsArray(o);
        }

        long t3 = System.nanoTime();
        for (int i = 0; i < rep; i++) {
            x+=checkClassName(o);
        }

        long t4 = System.nanoTime();

        System.out.println(t2 - t1);
        System.out.println(t3 - t2);
        System.out.println(t4 - t3);
    }

    private static int checkInstanceOf(Object[] o) {
        int i = 0;
        for (Object x : o) {
            if (x instanceof Object[]) i++;       // Perform some logic
            else if (x instanceof boolean[]) i++; // to keep the compiler or
            else if (x instanceof byte[]) i++;    // the JVM from optimising
            else if (x instanceof short[]) i++;   // this code away
            else if (x instanceof int[]) i++;
            else if (x instanceof long[]) i++;
            else if (x instanceof float[]) i++;
            else if (x instanceof double[]) i++;
            else if (x instanceof char[]) i++;
        }
        return i;
    }

    private static int checkIsArray(Object[] o) {
        int i = 0;
        for (Object x : o) {
            if (x != null && x.getClass().isArray()) i++;
        }
        return i;
    }

    private static int checkClassName(Object[] o) {
        int i = 0;
        for (Object x : o) {
            if (x != null && x.getClass().getName().charAt(0) == '[') i++;
        }
        return i;
    }
}

私は得ています:

394433000 // instanceof
110655000 // getClass().isArray()
396039000 // getClass().getName().charAt(0) == '['

したがって、一般的にgetClass().isArray()は、完全な一連のinstanceofチェックよりも遅いと主張することはできません。もちろん、私のテストを書き直すにはさまざまな方法がありますが、アイデアはわかります。

于 2013-04-23T13:52:08.957 に答える