Как получить доступ к вложенным HashMaps в Java? - PullRequest
28 голосов
/ 05 мая 2010

У меня есть HashMap на Java, к содержимому которого (как вы, наверное, все знаете) можно получить доступ

HashMap.get("keyname");

Если есть HashMap внутри другого HashMap, то есть вложенного HashMap, как я могу получить доступ к содержимому? Могу ли я сделать это следующим образом:

HashMap.get("keyname").get("nestedkeyname");

Спасибо.

Ответы [ 8 ]

62 голосов
/ 05 мая 2010

Вы можете сделать это, как вы и предполагали. Но ваш HashMap должен быть шаблонным:

Map<String, Map<String, String>> map = 
    new HashMap<String, Map<String, String>>();

В противном случае вы должны выполнить приведение к Map после извлечения второй карты из первой.

Map map = new HashMap();
((Map)map.get( "keyname" )).get( "nestedkeyname" );
8 голосов
/ 05 мая 2010

Да.

См .:

public static void main(String args[]) {

    HashMap<String, HashMap<String, Object>> map = new HashMap<String, HashMap<String,Object>>();
    map.put("key", new HashMap<String, Object>());
    map.get("key").put("key2", "val2");

    System.out.println(map.get("key").get("key2"));
}
5 голосов
/ 12 января 2017

Если вы планируете создавать HashMaps с переменной глубиной , используйте рекурсивную структуру данных .

Ниже приведена реализация, представляющая пример интерфейса:

class NestedMap<K, V> {

    private final HashMap<K, NestedMap> child;
    private V value;

    public NestedMap() {
        child = new HashMap<>();
        value = null;
    }

    public boolean hasChild(K k) {
        return this.child.containsKey(k);
    }

    public NestedMap<K, V> getChild(K k) {
        return this.child.get(k);
    }

    public void makeChild(K k) {
        this.child.put(k, new NestedMap());
    }

    public V getValue() {
        return value;
    }

    public void setValue(V v) {
        value = v;
    }
}

и пример использования:

class NestedMapIllustration {
    public static void main(String[] args) {

        NestedMap<Character, String> m = new NestedMap<>();

        m.makeChild('f');
        m.getChild('f').makeChild('o');
        m.getChild('f').getChild('o').makeChild('o');
        m.getChild('f').getChild('o').getChild('o').setValue("bar");

        System.out.println(
            "nested element at 'f' -> 'o' -> 'o' is " +
            m.getChild('f').getChild('o').getChild('o').getValue());
    }
}
5 голосов
/ 05 мая 2010

Как уже говорили другие, вы можете сделать это, но вы должны определить карту с помощью обобщений следующим образом:

Map<String, Map<String, String>> map = new HashMap<String, Map<String,String>>();

Однако, если вы просто слепо запустите следующее:

map.get("keyname").get("nestedkeyname");

вы получите исключение нулевого указателя, если имя ключа отсутствует на карте и ваша программа аварийно завершит работу. Вы действительно должны добавить следующую проверку:

String valueFromMap = null;
if(map.containsKey("keyname")){
  valueFromMap = map.get("keyname").get("nestedkeyname");
}
4 голосов
/ 05 мая 2010

Да, если вы используете правильную сигнатуру универсального типа для внешнего хэш-карты.

HashMap<String, HashMap<String, Foo>> hm = new HashMap<String, HashMap<String, Foobar>>();
// populate the map
hm.get("keyname").get("nestedkeyname");

Если вы не используете универсальные шаблоны, вам придется выполнить приведение, чтобы преобразовать объект, извлеченный из внешней хеш-карты, в HashMap (или, по крайней мере, Map), прежде чем вы сможете вызвать его get() метод. Но вы должны использовать дженерики; -)

3 голосов
/ 21 декабря 2017

Я предпочитаю создавать пользовательскую карту, которая расширяет HashMap. Затем просто переопределите get (), чтобы добавить дополнительную логику, чтобы, если карта не содержит ваш ключ. Он создаст новый экземпляр вложенной карты, добавит его и вернет.

public class KMap<K, V> extends HashMap<K, V> {

    public KMap() {
        super();
    }

    @Override
    public V get(Object key) {
        if (this.containsKey(key)) {
            return super.get(key);
        } else {
            Map<K, V> value = new KMap<K, V>();
            super.put((K)key, (V)value);
            return (V)value;
        }
    }
}

Теперь вы можете использовать его так:

Map<Integer, Map<Integer, Map<String, Object>>> nestedMap = new KMap<Integer, Map<Integer, Map<String, Object>>>();

Map<String, Object> map = (Map<String, Object>) nestedMap.get(1).get(2);
Object obj= new Object();
map.put(someKey, obj);
2 голосов
/ 02 января 2015

Я зашел на эту страницу StackOverflow в поисках чего-то известного из objc valueForKeyPath. Я также пришел с другим постом - «Кодирование значения ключа» для Java , но в итоге написал свой.

Я все еще ищу лучшее решение, чем PropertyUtils.getProperty в библиотеке beanutils apache.

Использование

Map<String, Object> json = ...
public String getOptionalFirstName() {
    return MyCode.getString(json, "contact", "firstName");
}

Осуществление

public static String getString(Object object, String key0, String key1) {
    if (key0 == null) {
        return null;
    }
    if (key1 == null) {
        return null;
    }
    if (object instanceof Map == false) {
        return null;
    }
    @SuppressWarnings("unchecked")
    Map<Object, Object> map = (Map<Object, Object>)object;
    Object object1 = map.get(key0);
    if (object1 instanceof Map == false) {
        return null;
    }
    @SuppressWarnings("unchecked")
    Map<Object, Object> map1 = (Map<Object, Object>)object1;
    Object valueObject = map1.get(key1);
    if (valueObject instanceof String == false) {
        return null;
    }
    return (String)valueObject;
}
0 голосов
/ 02 апреля 2019

Я попал в это обсуждение, пытаясь выяснить, как получить значение из вложенной карты неизвестной глубины, и это помогло мне найти следующее решение моей проблемы. Для оригинального вопроса это излишне, но, возможно, это будет полезно для кого-то, кто оказался в ситуации, когда у вас меньше знаний о поиске карты.

private static Object pullNestedVal(
        Map<Object, Object> vmap,
        Object ... keys) {
    if ((keys.length == 0) || (vmap.size() == 0)) {
        return null;
    } else if (keys.length == 1) {
        return vmap.get(keys[0]);
    }

    Object stageObj = vmap.get(keys[0]);
    if (stageObj instanceof Map) {
        Map<Object, Object> smap = (Map<Object, Object>) stageObj;
        Object[] skeys = Arrays.copyOfRange(keys, 1, keys.length);
        return pullNestedVal(smap, skeys);
    } else {
        return null;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...