19

在我的应用程序obj.getClass().isArray()中调用非常频繁,成为应用程序的瓶颈。
如果对象是数组,我想在运行时有效地检查。原始数组和对象数组应返回 true。
我能想象的方式是instanceof所有原始数组,但不能处理像 int[][] 这样的类型。并且该应用程序用作 lib,因此我无法列出所有类型。
有什么线索吗?

4

3 回答 3

8

isArray()是在运行时检查对象是否为数组实例的最有效方法。如果性能有问题,您可以使用以下方法之一来解决它:

  • 重构您的代码,以便分别处理数组对象和非数组对象,以便isArray()在编译时知道结果。
  • 使用局部变量和/或参数来缓存isArray()操作期间的值,因此只需要调用一次。
于 2013-04-23T13:32:18.983 回答
8

我刚刚做的一个基准测试给出了以下结果:

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

基准测试是使用Benchmark.java完成的,用Main.java调用。


final在上述基准测试中讨论了变量的使用之后,使用本地变量查看新结果:

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

即使持续时间有点长(顺便说一句很有趣),它们的顺序也被保留了。

然后使用这个新的Main.java调用 Benchmark.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 回答