我正在开发一个应用程序,其中一个设计方法涉及到大量使用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
德米安和保罗提到了一个很好的观点;然而,要执行的代码的位置实际上取决于你想如何使用数据……
我非常喜欢可以以多种方式使用的小型数据对象。如果你采用覆盖(多态)方法,你的对象只能被“一种方式”使用。
这就是模式发挥作用的地方……
您可以使用双重分派(如在访问者模式中)要求每个对象传递自身“调用您”——这将解析对象的类型。但是(再次),您需要一个可以对所有可能的子类型“做一些事情”的类。
我更喜欢使用策略模式,在这种模式下,您可以为想要处理的每个子类型注册策略。大致如下。注意,这只有助于精确的类型匹配,但它具有可扩展的优势——第三方贡献者可以添加自己的类型和处理程序。(这对于OSGi这样的动态框架很好,可以添加新的包)
希望这能激发一些其他的想法……
package com.javadude.sample;
import java.util.HashMap;
import java.util.Map;
public class StrategyExample {
static class SomeCommonSuperType {}
static class SubType1 extends SomeCommonSuperType {}
static class SubType2 extends SomeCommonSuperType {}
static class SubType3 extends SomeCommonSuperType {}
static interface Handler<T extends SomeCommonSuperType> {
Object handle(T object);
}
static class HandlerMap {
private Map<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>> handlers_ =
new HashMap<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>>();
public <T extends SomeCommonSuperType> void add(Class<T> c, Handler<T> handler) {
handlers_.put(c, handler);
}
@SuppressWarnings("unchecked")
public <T extends SomeCommonSuperType> Object handle(T o) {
return ((Handler<T>) handlers_.get(o.getClass())).handle(o);
}
}
public static void main(String[] args) {
HandlerMap handlerMap = new HandlerMap();
handlerMap.add(SubType1.class, new Handler<SubType1>() {
@Override public Object handle(SubType1 object) {
System.out.println("Handling SubType1");
return null;
} });
handlerMap.add(SubType2.class, new Handler<SubType2>() {
@Override public Object handle(SubType2 object) {
System.out.println("Handling SubType2");
return null;
} });
handlerMap.add(SubType3.class, new Handler<SubType3>() {
@Override public Object handle(SubType3 object) {
System.out.println("Handling SubType3");
return null;
} });
SubType1 subType1 = new SubType1();
handlerMap.handle(subType1);
SubType2 subType2 = new SubType2();
handlerMap.handle(subType2);
SubType3 subType3 = new SubType3();
handlerMap.handle(subType3);
}
}