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 ); }
您可以执行以下操作:
- 向
ICachableInterface
接口添加一个方法,ICachableInterface
接口将处理将对象放入两个Maps之一,作为方法的参数给出。 - 在每个实现类中实现此方法,让每个类决定将自己放入哪个Map。
- 删除for循环中的
instanceof
检查,并使用对步骤1中定义的新方法的调用替换put
方法。
但是,这不是一个好的设计,因为如果你有另一个实现这个接口的类和第三个映射,那么你需要将另一个Map传递给你的新方法。