Is there something wrong with instanceof checking here?

With the introduction of generics, I am reluctant to do instanceof or cast as much as possible. But I do not see the way in this scenario:

for (CacheableObject<ICacheable> 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); } } 

In the code above, I know that my ICacheables should only be instances of MyObject or OtherObject, and depending on this, I want to put them on 2 separate cards, and then do some processing further.

I would be wondering if there is another way to do this without checking the instance.

thanks

+4
source share
3 answers

You can use double call. No promises is the best solution, but it is an alternative.

Code example

 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<String, MyObject> myObjects = new HashMap<String, MyObject>(); private HashMap<String, OtherObject> otherObjects = new HashMap<String, OtherObject>(); 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); } } 

The idea here is that instead of casting or using instanceof you call the iCacheable object .put(...) method, which returns to the overloaded methods of the Example object. Which method is called depends on the type of this object.

See also visitor template . My code sample smells because the ICacheable.put(...) method is incompatible - but using the interfaces defined in the Visitor template can clear this smell.

Why can't I just call this.put(iCacheable) from the Example class?

In Java, redefinition is always bound at run time, but overloading is a bit more complicated: dynamic dispatch means that the implementation of the method will be selected at run time, but the signature of the method is nevertheless determined at compile time. (Refer to the Java Language Specification, chapter 8.4.9 for more information, and see the β€œMaking Hash of It” puzzle on page 137 of the Java Puzzlers book.)

+2
source

Is there no way to combine the cached objects in each card into one card? Their keys could keep them separate so you can store them on the same card. If you cannot do this, you can have

 Map<Class,Map<Key,ICacheable>> 

then do the following:

 Map<Class,Map<Key,ICacheable>> cache = ...; public void cache( ICacheable cacheable ) { if( cache.containsKey( cacheable.getClass() ) { cache.put( cacheable.getClass(), new Map<Key,ICacheable>() ); } cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable ); } 
+1
source

You can do the following:

  • Add a method to your ICachableInterface interface, which will handle the placement of the object in one of the two Maps specified as arguments to the method.
  • Implement this method in each of the two implementing classes so that each class decides which Card places itself.
  • Remove the instanceof checks in the for loop and replace the put method with a call to the new method defined in step 1.

This is not a very good design, because if you ever had a different class that implements this interface and a third map, you will need to pass another map to your new method.

0
source

Source: https://habr.com/ru/post/1443755/


All Articles