开发者

An Hashmap with a finite set of keys that each accept only one type of value?

开发者 https://www.devze.com 2023-03-19 10:47 出处:网络
Ok, this might be a little hard to explain. I\'m looking for a way to build a Hashmap of some sort, which will be populated with keys that I already know (because they are properties of the object I a

Ok, this might be a little hard to explain. I'm looking for a way to build a Hashmap of some sort, which will be populated with keys that I already know (because they are properties of the object I am crea开发者_运维问答ting). Each of these known keys will have values that are either a String, an int or float (which will be autoboxed), or - later - some kind of object/ function (I still don't know how I'll do that part, but it'll be further along the way anyway). I also want to set which type accepts each of the key (say key "x" will only accept an Integer type of value, key "equation" will only accept a string, etc.).

Just to give more context, my goal is to build a Tweener utility, as I found no such library in Java, except for SumoTween, that doesn't fit my needs at all. I'm kind of trying to build my classes the way Caurina is. If you have a better alternative that would save me time and trouble, please feel free to share (be it about Tweeners or about my Hashmap question). By the way, I'm doing this Tweener to use it in an Android game I'm building, in order to do animations on bitmap/drawable objects (can't use the animation classes for those afaik).

PS : This is my first question on this website, I hope I don't sound too confused; Please bear with me.


Why are you using a hashmap for this? If you have known "keys", just make a class with those members and then you can type them however you want.

If you really must use a hashmap for some reason, you can just extend it and override the put() method to check for your magic values. But I strongly recommend against that, it's poor design.


If I understand you correctly, you are basically looking for a HashMap. Is that correct?

PS Yes, I know that using "Object" that way isn't very pretty.


I'm not entirely sure if this is what you're asking for, but it sounds like you could use some kind of interface/abstract class for the key and implement/extend it appropriately for each key type, e.g.:

public interface Key {}

private static final class StringKey implements Key {
    private final String value;

    public StringKey(String value) {
        this.value = value;
    }

    // hashCode, equals here
}

// IntegerKey, FloatKey, etc similarly

Then have something like:

HashMap<Key, Integer> map = new HashMap<Key, Integer>();


I'd say create a custom class that inherits from say HashMap, on insert you check the specified key/value if it's valid.

public static final HashMap<String, Class<?>> allowedTypes = new HashMap<String, Class<?>>() {{
    put("key1", String.class);
    put("key2", Integer.class);
    // etc
}};

public class CustomHashMap extends HashMap {
    public Object put(Object key, Object value) {
        Class<?> type = allowedTypes(key);

        if(type != null && !type.isInstance(value))
            throw new IllegalArgumentException("Invalid type for key " + key);

        return put(key, value);
    }

    private void PutAll(Map m) {
        for(Entry<?, ?> entry : m.entrySet())
            put(entry.getKey(), entry.getValue());
    }
}


You could have separate maps, one for the Strings; another for the Integers, etc. And when adding to any of these maps, you could add the key to a (global) set, to ensure that no key is duplicated across maps. I suspect that wouldn't meet your needs very well (and of course the lookup is a little more involved), but if it works for you, great.

Maybe a better option is to add another level of indirection. Make your map a Hashmap where YourThing has subclasses for each of the types you want to hold. So, a StringYourThing has a String data member; an IntegerYourThing has an int data member, etc. I wouldn't be surprised to find that YourThing starts to take on functionality that is currently a switch statement somewhere inside another class that is trying to deal consistently with all these different data types. If that class could simply interact with a YourThing, it could get simpler. But it's hard to know without seeing your code.


I would rather avoid using map directly. What you are looking for is probably something more application specific:

Assume the whole thing you are building is for bunch of settings. Your "Setting" will have a predefined set of key. Each key is predefined to accept corresponding setting value of specific value. If incorrect type is provided, exception will be thrown.

I think something roughly like this is reasonable:

enum SettingValueType {
  public boolean isCorrectType(Object obj) {
    return true if obj is correct type represented by this enum 
  }
  STRING, INT, FLOAT   // add support to other type if u want
};

clsss SettingValue {
  SettingValueType type;
  Object value;
}

class SettingRepo {  // a repository of setting entries
  private Map<String, SettingValueType> allowedKeyAndType;
  private Map<String, Object> settings;

  SettingRepo() {
    // setup allowedKeyAndType programmatically or from config etc, depends on your design
  }

  public SettingValue setSetting(String key, Object value)  {

    SettingValueType valueType = allowedKeyAndType.get(key);
    if (valueType == null) {
      throw new KeyNotAllowedException();
    }

    if (v!alueType.isCorrectType(value) {
      throw new ValueIncorectTypeException();
    }

    return settings.put(key, new SettingValue(valueType, value));
    }
  } 

  public SettingValue getSetting(String key) {
    // u may throw exception if key is not in predefined set

    return settings.get(key);
  }

  // u may consider adding some convinient methods too:
  public String setStringSetting(String key, String value) {
    if alllowedKeyAndType do not contains key {
      throw KeyNOtAllowedException
    }
    if type is not STRING {
      throw IncorrectTypeExceptin
    }
    settings.put(key, new SettingValue(STRING, value))
  }

  public String getStringSetting(String key) {
    // should be straight forward now, right?
  }    
}

There are lots of place that can be improved according to your usage: if ur types are very dynamic, u may make SettingValueType something like a bunch of strategies, or use Class directly. setSetting() can made generic and take Class as extra parameter etc. But at least, this should give u a starting point.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号