2016-04-18 3 views
0

Я пытаюсь создать пользовательский интерфейс с HashMap. Пользователи могут изменять значения и изменять имя клавиш, не нарушая порядок ключей. Я искал и нашел LinkedHashMap. Который сохранил порядок ключей в большинстве случаев. Но когда я удаляю ключ и добавляю его обратно после его переименования, он всегда добавляет его до конца. Поэтому я переопределил класс LinkedHashMap и добавил функцию changeKeyName().JAVA - Выполненная реализация HashMap с функцией изменения имени ключа

Теперь это работает (в моем случае), но мне было интересно, можно ли его улучшить и сделать надежным. Я только переопределил функции, которые я использовал. Какие другие функции нужно переопределить, чтобы завершить?

Заранее спасибо.

Вот код:

private static class OrderedHashMap<K, V> extends LinkedHashMap<K, V> { 

     ArrayList<K> keys = new ArrayList<K>(); 

     @Override 
     public V put(K key, V value) { 
      if (!keys.contains(key)) 
       keys.add(key); 
      return super.put(key, value); 
     } 

     @Override 
     public V remove(Object key) { 
      keys.remove(key); 
      return super.remove(key); 
     } 

     @Override 
     public Set<K> keySet() { 
      LinkedHashSet<K> keys = new LinkedHashSet<K>(); 
      for (K key : this.keys) { 
       keys.add(key); 
      } 
      return keys; 
     } 

     public void changeKeyName(K oldKeyName, K newKeyName) { 
      int index = keys.indexOf(oldKeyName); 
      keys.add(index, newKeyName); 
      keys.remove(keys.get(index + 1)); 
      V value = super.get(oldKeyName); 
      super.remove(oldKeyName); 
      super.put(newKeyName, value); 
     } 

     @Override 
     public Set<Map.Entry<K, V>> entrySet() { 
      final OrderedHashMap<K, V> copy = this; 
      LinkedHashSet<Map.Entry<K, V>> keys = new LinkedHashSet<Map.Entry<K, V>>(); 
      for (final K key : this.keys) { 
       final V value = super.get(key); 
       keys.add(new Map.Entry<K, V>() { 
        @Override 
        public K getKey() { 
         return key; 
        } 

        @Override 
        public V getValue() { 
         return value; 
        } 

        @Override 
        public V setValue(V value) { 
         return copy.put(getKey(), value); 
        } 
       }); 
      } 
      return keys; 
     } 
    } 

EDIT: Я думаю почему не было достаточно ясно. Скажем, мы добавили ключи ниже.

{"key1":"value1"}, 
{"key2":"value2"}, 
{"key3":"value3"}, 
{"key4":"value4"} 

И, например, я хочу изменить имя ключа «key2». Но поскольку это также пользовательский интерфейс, порядок ключей должен оставаться неизменным.
Я провел некоторое исследование, и я узнал, что, кроме удаления ключа и повторного ввода нового имени ключа с одинаковым значением, ничего не может быть сделано. Так что, если мы делаем это и изменить «key2» на «key2a»:

{"key1":"value1"}, 
{"key3":"value3"}, 
{"key4":"value4"}, 
{"key2a":"value2"} 

И то, что я хочу это:

{"key1":"value1"}, 
{"key2a":"value2"}, 
{"key3":"value3"}, 
{"key4":"value4"} 

Так что я просто держал ключи в ArrayList и возвращали их, когда entrySet() и keySet().

+1

** НЕТ ** изменить * ключи *; если вы это сделаете, то ваши «Map.Entry» (ы) будут в неправильных хэш-ведрах! –

+0

@ElliottFrisch Итак, я не должен переопределять функции 'entrySet()' и 'keySet()'? Потому что я действительно не изменяю ключ, но удаляю и добавляю его с новым именем. – ossobuko

+0

Пожалуйста, добавьте код, который вызывает * changeKeyName() * –

ответ

0

Рассматривались ли вы просто с использованием класса TreeMap вместо пользовательского подкласса LinkedHashMap? Он будет поддерживать порядок, если вы реализуете интерфейс Comparable на клавишах.

0

Если вы хотите иметь возможность изменять ключи, не влияя на функцию хэширования в коллекции, где хранится значение, попробуйте создать собственный класс, например;

private class VariableKeyMap { 

    private LinkedHashSet<K, V> myCollection = new LinkedHashSet<K, V>(); 
    private HashMap<int, K> aliases = new HashMap<int, K>(); 
    int id = 0; 

    public void addEntry(K key, V value) { 
     id += 1; 
     aliases.put(K, id); 
     myCollection.put(id, V); 
    } 

    public V getValue(K key) { 
     return myCollection.get(aliases.get(key)); 
    } 

    ... 
} 

Вы можете обновить свой псевдоним ключа, не затрагивая, где фактически хранится значение;

public void changeKey(K oldKey, K newKey) { 
    int currentId = aliases.get(oldKey); 
    aliases.remove(oldKey); 
    aliases.put(newKey, currentId); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^