我正在开发一个应用程序,其中一个设计方法涉及到大量使用instanceof操作符。虽然我知道OO设计通常试图避免使用instanceof,但那是另一回事,这个问题纯粹与性能有关。我想知道是否对性能有影响?和==一样快吗?

例如,我有一个有10个子类的基类。在接受基类的单个函数中,我检查类是否是子类的实例并执行一些例程。

我想到的另一种解决方法是使用“type id”整数原语,并使用位掩码来表示子类的类别,然后对子类“type id”与表示类别的常量掩码进行位掩码比较。

instanceof是否被JVM优化得更快?我想坚持使用Java,但应用程序的性能至关重要。如果有人曾经在这条路上走过,可以提供一些建议,那就太棒了。我是不是太挑剔了,或者专注在错误的地方去优化?


当前回答

将决定性能影响的项目有:

The number of possible classes for which the instanceof operator could return true The distribution of your data - are most of the instanceof operations resolved in the first or second attempt? You'll want to put your most likely to return true operations first. The deployment environment. Running on a Sun Solaris VM is significantly different than Sun's Windows JVM. Solaris will run in 'server' mode by default, while Windows will run in client mode. The JIT optimizations on Solaris, will make all method access able the same.

我为四种不同的分派方法创建了一个微基准测试。Solaris的结果如下所示,数值越小越快:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 

其他回答

我只是做了一个简单的测试,看看instanceOf的性能如何与对一个只有一个字母的字符串对象的简单s.equals()调用进行比较。

在10.000.000循环中,instanceOf给了我63-96ms,而字符串equals给了我106-230ms

我使用java jvm 6。

所以在我的简单测试中,做一个instanceOf而不是一个字符串比较更快。

使用Integer的.equals()而不是string的给了我相同的结果,只有当我使用== I比instanceOf快20ms(在10.000.000循环中)

一般来说,在这种情况下(instanceof检查这个基类的子类)不支持使用“instanceof”操作符的原因是,您应该做的是将操作移动到一个方法中,并为适当的子类重写它。例如,如果你有:

if (o instanceof Class1)
   doThis();
else if (o instanceof Class2)
   doThat();
//...

你可以用

o.doEverything();

然后在Class1中调用“doEverything()”的实现,在Class2中调用“doThat()”,以此类推。

Instanceof非常快。它可以归结为用于类引用比较的字节码。在一个循环中尝试几百万个实例,自己看看。

回答你的最后一个问题:除非分析人员告诉你,你在某个实例上花费了大量的时间:是的,你在吹毛求疵。

在考虑优化从来不需要优化的东西之前:以最易读的方式编写算法并运行它。运行它,直到jit编译器有机会优化它自己。如果这段代码有问题,可以使用分析器来告诉您,在哪里可以获得最大收益并进行优化。

在高度优化编译器的时代,您对瓶颈的猜测很可能是完全错误的。

在这个答案的真正精神(我完全相信):一旦jit编译器有机会优化它,我绝对不知道instanceof和==是如何关联的。

我忘了:永远不要测量第一次运行。

You're focusing on the wrong thing. The difference between instanceof and any other method for checking the same thing would probably not even be measurable. If performance is critical then Java is probably the wrong language. The major reason being that you can't control when the VM decides it wants to go collect garbage, which can take the CPU to 100% for several seconds in a large program (MagicDraw 10 was great for that). Unless you are in control of every computer this program will run on you can't guarantee which version of JVM it will be on, and many of the older ones had major speed issues. If it's a small app you may be ok with Java, but if you are constantly reading and discarding data then you will notice when the GC kicks in.