instanceof检查有什么问题吗?

随着generics的引入,我不愿意尽可能地执行实例或转换。 但在这种情况下,我没有看到解决方法:

for (CacheableObject cacheableObject : cacheableObjects) { ICacheable iCacheable = cacheableObject.getObject(); if (iCacheable instanceof MyObject) { MyObject myObject = (MyObject) iCacheable; myObjects.put(myObject.getKey(), myObject); } else if (iCacheable instanceof OtherObject) { OtherObject otherObject = (OtherObject) iCacheable; otherObjects.put(otherObject.getKey(), otherObject); } } 

在上面的代码中,我知道我的ICacheables应该只是MyObject或OtherObject的实例,并且根据这一点,我想将它们放入2个单独的映射中,然后再进行一些处理。

如果没有我的检查实例,我还有其他方法可以做到这一点。

谢谢

你可以使用双重调用。 没有承诺它是一个更好的解决方案,但它是另一种选择。

代码示例

 import java.util.HashMap; public class Example { public static void main(String[] argv) { Example ex = new Example(); ICacheable[] cacheableObjects = new ICacheable[]{new MyObject(), new OtherObject()}; for (ICacheable iCacheable : cacheableObjects) { // depending on whether the object is a MyObject or an OtherObject, // the .put(Example) method will double dispatch to either // the put(MyObject) or put(OtherObject) method, below iCacheable.put(ex); } System.out.println("myObjects: "+ex.myObjects.size()); System.out.println("otherObjects: "+ex.otherObjects.size()); } private HashMap myObjects = new HashMap(); private HashMap otherObjects = new HashMap(); public Example() { } public void put(MyObject myObject) { myObjects.put(myObject.getKey(), myObject); } public void put(OtherObject otherObject) { otherObjects.put(otherObject.getKey(), otherObject); } } interface ICacheable { public String getKey(); public void put(Example ex); } class MyObject implements ICacheable { public String getKey() { return "MyObject"+this.hashCode(); } public void put(Example ex) { ex.put(this); } } class OtherObject implements ICacheable { public String getKey() { return "OtherObject"+this.hashCode(); } public void put(Example ex) { ex.put(this); } } 

这里的想法是 – 不是转换或使用instanceof – 而是调用iCacheable对象的.put(...)方法,该方法将自身传递回Example对象的重载方法。 调用哪种方法取决于该对象的类型。

另请参阅访客模式 。 我的代码示例闻起来因为ICacheable.put(...)方法不完整 – 但使用Visitor模式中定义的接口可以清除这种气味。

为什么我不能从Example类中调用this.put(iCacheable)

在Java中,覆盖总是在运行时绑定,但重载稍微复杂一点:动态调度意味着将在运行时选择方法的实现,但是方法的签名仍然在编译时确定。 (有关详细信息,请查看Java语言规范,第8.4.9章 ,另请参阅Java Puzzlers一书第137页上的益智游戏“制作它的哈希”。)

有没有办法将每个地图中的缓存对象合并为一个地图? 它们的键可以将它们分开,这样您就可以将它们存储在一个地图中。 如果你做不到那么你可以有一个

 Map> 

然后这样做:

 Map> cache = ...; public void cache( ICacheable cacheable ) { if( cache.containsKey( cacheable.getClass() ) { cache.put( cacheable.getClass(), new Map() ); } cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable ); } 

您可以执行以下操作:

  1. ICachableInterface接口添加一个方法, ICachableInterface接口将处理将对象放入两个Maps之一,作为方法的参数给出。
  2. 在每个实现类中实现此方法,让每个类决定将自己放入哪个Map。
  3. 删除for循环中的instanceof检查,并使用对步骤1中定义的新方法的调用替换put方法。

但是,这不是一个好的设计,因为如果你有另一个实现这个接口的类和第三个映射,那么你需要将另一个Map传递给你的新方法。