Object.isArray()很慢,有没有快速的方法呢?

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

我刚刚完成的基准测试给出了以下结果:

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

Benchmark已经使用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 

结果顺序仍然相同。

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

  • 重构代码,以便单独处理数组对象和非数组对象,因此isArray()的结果在编译时是已知的。
  • 在操作期间使用局部变量和/或参数来缓存isArray()的值,因此只需要调用一次。

根据您的意见,我得出结论,在调查分析结果时,您可能会遇到解释性错误。 您的探查器的方法级检测可能会严重削弱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检查要慢。 当然,有很多不同的方法来重写我的测试,但你明白了。