在我的应用程序obj.getClass().isArray()
被称为非常频繁,成为应用程序的瓶颈。
我想在运行时高效地检查对象是否是数组。 基元数组和对象数组应该返回true。
我可以想象的方式是instanceof
所有原始数组,但不能处理int [] []类型。该应用程序用作lib,所以我不能列出所有类型。
有什么线索吗?Object.isArray()很慢,有没有一种快速的方法来做到这一点?
回答
我刚刚做了一个基准测试结果如下:
{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
即使持续时间都长一点(有趣的BTW) ,他们的顺序一直保存下来。
Benchmark.java已被随后调用这个新的Main.java。
而使用称为与该其他Main.java基本数组:
{a instanceof int[]} spends 71ms
{a.getClass().getName().charAt(0) == '['} spends 82ms
{a.getClass().isArray()} spends 340ms
仍然相同的结果顺序。
您可以发布基准代码吗?我得到了[相反的结果](http://stackoverflow.com/a/16171137/521799) – 2013-04-23 13:58:47
@LukasEder [Benchmark.java](http://pastebin.com/pskJ1tSy)和[Main.java](http: //pastebin.com/KbptdWaB)。我必须说这是我自己开发的工具,所以我希望它没有错。不要犹豫,告诉我,如果你注意到一个虽然,也许我做错了:) – sp00m 2013-04-23 14:05:45
是的,我怀疑'布尔b = s instanceof对象[];'是由编译器优化,因为's'是'最后'和上面的表达式因此总是评估为真... – 2013-04-23 14:08:04
isArray()
是在运行时检查对象是否为数组实例的最有效方法。如果性能是一个问题,你可以使用下列方法之一来解决这个问题:
- 重构代码,以便数组对象和非数组对象是分开处理的,所以
isArray()
结果在编译时已知。 - 在操作过程中使用局部变量和/或参数来缓存
isArray()
的值,因此只需调用一次即可。
我同意重构,但任何人都可以请他们声明'isArray()'比'instanceof'慢得多吗?我认为缓存结果可能会造成更多的伤害,而不是解决问题! – 2013-04-23 14:03:03
看来你的(未经证实的)声明'usArray()'最快是错误的 - 请参阅sp00n的答案。尽管我同意这些建议。 – Bohemian 2013-04-23 14:24:28
@波希米亚:sp00m的测试可能不准确,请参阅评论... – 2013-04-23 14:26:37
从您的意见中,我可以得出结论,您在调查分析结果时可能会遭受解释错误。您的配置文件的方法级别的检测可能会严重影响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
检查慢。当然,有很多不同的方法来重写我的测试,但你明白了。
这个基准是有缺陷的。它不考虑JVM热身。 (我不会感到惊讶,你会通过以另一种顺序进行测试而得到相反的“结果”......) – 2013-04-23 14:08:36
@StephenC:我当然想到了这一点,并试过两种方法。我会更新结果... – 2013-04-23 14:13:07
- 1. 有没有更快的方法来做到这一点?
- 2. 有没有更快的方法来做到这一点?
- 3. Multi-Table Selfjoins - 有没有一个很好的方法来做到这一点?
- 4. coldfusion CRUD,必须有一个快速的方法来做到这一点
- 5. 有没有更有效的方法来做到这一点?
- 6. 有很多:通过,更好的方法来做到这一点?
- 7. 有没有一种快速的方法来从点或分支来源“git diff”?
- 8. 有没有更好的方法来做到这一点?
- 9. 有没有更简单的方法来做到这一点?
- 10. 有没有更好的方法来做到这一点在PHP
- 11. 有没有更好的方法来做到这一点?
- 12. 有没有更好的方法来做到这一点?
- 13. 有没有更简单的方法来做到这一点?
- 14. 有没有更好的方法来做到这一点?
- 15. 有没有更多的CoffeeScripty方法来做到这一点?
- 16. 有没有更好的方法来做到这一点? BASH
- 17. 有没有一种快速找到约束所在的方法?
- 18. 有没有办法做到这一点?
- 19. 还有没有使用宏定义做到这一点的另一种方法?
- 20. 有没有更好的方法来做到这一点没有反思?
- 21. 根据大型XSD验证大型XML文件,有没有快速的方法来做到这一点?
- 22. 有没有更好的方式来做到这一点链接
- 23. .htaccess有没有更高效的方式来做到这一点?
- 24. 有没有一种更新SQL中很多记录的快速方法?
- 25. 有没有一个更好的方法来做到这一点 - php max()
- 26. 有没有一种快速的方法可以下载所有这些图像?
- 27. 有没有一种快速解锁Emacs中的键的方法?
- 28. 有没有一种很好的,安全的,快速的方法来写入InputStream到Scala中的文件?
- 29. 有没有一种快速有效的方法来在Javascript中乘数组?
- 30. jquery验证 - 有没有更有效的方法来做到这一点?
这不回答你的问题,但它是一个很好的补充讨论:http://stackoverflow.com/questions/219881/java-array-reflection-isarray-vs-instanceof – 2013-04-23 13:27:35
我认为这个问题是为什么你必须经常调用该方法?我希望如果有更快的方法,JDK开发人员会将其实现基于它。如果没有,你必须提供你正在试图解决的实际问题的更多细节。 – Axel 2013-04-23 13:30:45
你的'instanceof'推理不完全正确。 'int [] [] instanceof Object []'产生'true'(就像'int [] instanceof Object'一样),所以这些情况都被覆盖了......不确定这是否与你的实际问题域相关, Axel的评论)。 – 2013-04-23 13:33:35