4

I want to extend HashMap to add the method putIfGreaterThan which basically retrieves the value for a given key and if the new value is greater than the old value we update the old value with the new value. Like this:

  public void putIfGreaterThan(String key, Double value )
  {

  if (containsKey(key ) != true) {
  put( key , value );
  } else {
  if (get(key ) < value) {
  System. out .println("Adding new value: " + value + " to map" );
  put( key , value );
  } else {
  System. out .println("Did not add value: " + value + " to map" );
  }
  }


  }

The program above works fine - however I would like to add this method to both HashMap and LinkedHashMap. In other words, if someone instantiates:

HashMap hashmap = new HashMap();

They should be able to access the method:

hashmap.putIfGreaterThan();

And if someone instantiates:

LinkedHashMap linkedhashmap = new LinkedHashMap();

They should be able to access the method:

linkedhashmap .putIfGreaterThan();

If I create a new class as follows:

MyHashMap extends HashMap<String, Double> and add the previously mentioned method - I am only extending HashMap not LinkedHashMap. This would not allow me to access the method if I instantiate a LinkedHashMap.

I was thinking of modifying the source code in the original HashMap class (by adding the method putIfGreaterThan) however I am unable to modify the source code unless I de-compile the entire class (and when I try doing this I get a bunch of other errors so I figured it would be easier just to extend the HashMap class but doing this means I cannot use the method putIfGreaterThan on both HashMap and LinkedHashMap).

Further, if I had added the method to the original class one would be able to call this method on any HashMap (even if the map contains two Strings) but the method is only applicable on a HashMap that contains String and Double or String and Int. Hence, I think it makes more sense to extend the original class and customize the current class with methods related to a HashMap of String and Double.

Any suggestions?

Thanks

Kevin Little
  • 263
  • 1
  • 4
  • 10
  • 2
    I would suggest using composition. Make your class have a hashmap, then wrap the put method of the map with your logic. – chatton Mar 10 '17 at 18:28
  • Modifying the behavior of the HashMap class itself, not just your own custom class, cannot be done, and for good reason: it would introduce a security nightmare for Java applications everywhere. – VGR Mar 10 '17 at 18:51
  • Why the redundant `if (containsKey(key ) != true)` instead of the straightforward `if (! containsKey(key))`? – Lew Bloch Mar 10 '17 at 19:06
  • Don't modify the core API. You're aware that Java forbids multiple inheritance of implementation (classes), and only permits multiple inheritance of interfaces, right? – Lew Bloch Mar 10 '17 at 19:08

3 Answers3

2

Let your custom map implement the Map interface instead and wrap a concrete map with it that is provided by the user of the class via the constructor:

public class MyMap implements Map<String, Double>{
    private final Map<String, Double> map;  

    public MyMap(Map<String, Double> map){
        this.map = map;
    }

    public void putIfGreaterThan(String key, Double value ){...}

    @Override
    public int size() {
        return map.size();
    }

    //inherited methods
}

This class can be used like this:

MyMap map = new MyMap(new LinkedHashMap<>());

or:

MyMap map = new MyMap(new HashMap<>());
Calculator
  • 2,769
  • 1
  • 13
  • 18
  • Shouldn't you use `putIfGreaterThan(K key, V value)` here? – NAMS Mar 10 '17 at 18:35
  • If I implement the Map interface I am forced to add 12 unimplemented methods such as size(), containsKey() and isEmpty(). I now need to add the body to each method. Seems like a lot of extra work just to define 1 new method.. – Kevin Little Mar 13 '17 at 16:05
  • @KevinLittle You only need to call the corresponding method of the wrapped map in the bodies of the inherited methods like I did for `size()` in my answer: `public boolean isEmpty(){return map.isEmpty()}` and so on – Calculator Mar 13 '17 at 19:47
  • OK makes sense. I think I'm going to accept this answer however I was wondering why this method is superior than the method suggested by @chatton (to use composition) - I do not need to add unimplemented methods with that strategy.. Also why do you suggest I use K, V over (if I'm only defining methods that apply to String, Double or String, Int) Thanks! – Kevin Little Mar 14 '17 at 01:49
  • @KevinLittle If you want a String, Double map `` makes sense - I changed it. Wrapping a given map is composition - the custom map HAS an other map. The benefit you get of additionally implementing the Map interface is that the custom map not only HAS a map, but also IS a map itself. This way you can use the custom map like any other map. – Calculator Mar 14 '17 at 19:12
0

Java don't support multi inheritance, but you can be done using Interfaces.

Java Multiple Inheritance

Community
  • 1
  • 1
Marcos Bergamo
  • 1,073
  • 2
  • 11
  • 19
0

You cannot add your method to the existing HashMap or LinkedHashMap class. Only way is to create a custom class MyHashMap<K,V> which implements the Map interface and put your logic there and compose that class with HashMap and(or) LinkedHashMap and let your clients operate on MyHashMap.

Thiyagu
  • 17,362
  • 5
  • 42
  • 79