2013-02-12 3 views
2

Итак, я хочу составить карту списков строк в строках, но я не могу заставить ее работать правильно:HashMap of ArrayList <String>, String работает неправильно?

это весь код, который я сделал, и пока я не смогу узнать, почему, я не могу прогрессировать :

Map<List<String>, String> test = new HashMap<List<String>, String>(); 
test.put(new ArrayList<String>(), "s1"); 
test.put(new ArrayList<String>(), "s2"); 
test.put(new ArrayList<String>(), "s3"); 

System.out.println(test.size()); 

Я получаю 1, это должно быть 3! Почему добавляется только один объект, когда я сделал 3 вызова, для 3 отдельных объектов? Я знаю опасность случайного добавления в один объект к коллекции, но я специально создал новый ArrayList для каждого put, создав тем самым совершенно новый новый объект.

Так почему же на карте есть только один объект? Спасибо!

+2

Вы никогда не должны использовать изменяемый ключ в HashMap. –

ответ

2

ArrayList # hashCode() возвращает то же самое для всех из них. Если вы посмотрите на источник для него: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/AbstractList.java#AbstractList.hashCode%28%29

Вы можете видеть, что не должно быть элементов или всех тех же элементов, что hashCode будет одинаковым.

Закрепите это и оно должно работать нормально. Используйте либо карту, либо измените хэш-код так или иначе.

+0

спасибо, как мне изменить hashCode? устранит проблему TreeMap? –

+0

Это отлично работает. Вы можете переопределить ArrayList и просто изменить метод hashCode. Например, сделайте его уникальным идентификатором, например, например: время создания, произвольно сгенерированное число и т. Д. – 2013-02-12 06:35:00

3

Попробуйте это:

Map<String,List<String>> test = new HashMap<String,List<String>>(); 
test.put("s1", new ArrayList<String>()); 
test.put("s2", new ArrayList<String>()); 
test.put("s3", new ArrayList<String>()); 

System.out.println(test.size()); 

Обратите внимание, что карта является key-value отношение. По этой причине вы также можете использовать String в качестве ключ и ArrayList как значения, а не наоборот. Таким образом, если вы добавите 3 разных строки, каждый из них будет иметь другое значение хэша (hashcode). Таким образом, у вас будет 3 разных ключа в вашем Map.

Следует также отметить, что:

поставил

общественного объект положить (ключ объекта, значения Object) Связывает указанное значение с указанным ключом в этой карте. Если на карте ранее было отображено для этого ключа, старое значение заменено.

Именно поэтому вы получаете 1, а не 3, потому что вы добавляли тот же объект new ArrayList<String>().

Подробнее см. В спецификациях Class HashM.

1

Вы можете использовать ArrayList в качестве ключа, попробуйте

System.out.println(new ArrayList<String>().equals(new ArrayList<String>())); 

печатает

true 
+0

Equals не совпадает с хеш-кодом. – 2013-02-12 06:34:04

+1

Общий контракт для hashCode: если два объекта равны в соответствии с методом equals (Object), то вызов метода hashCode для каждого из двух объектов должен давать одинаковый целочисленный результат. –

0

Наилучшим подходом было бы использовать объект String, как ключ и список в качестве значения.

Посмотрите, что говорят java docs here.

И если вы хотите добавить ArrayList в качестве ключа, тогда необходимо переопределить метод equals.

Сообщение here дает хорошее представление. Я положил некоторые, которые мне понравились с этой должности.

Перекрытие составляет два ArrayLists:

public boolean equals(List<String> one, List<String> two){ 
    if (one == null && two == null){ 
     return true; 
    } 

    if((one == null && two != null) 
     || one != null && two == null 
     || one.size() != two.size()){ 
     return false; 
    } 

    //to avoid messing the order of the lists we will use a copy 
    //as noted in comments by A. R. S. 
    one = new ArrayList<String>(one); 
    two = new ArrayList<String>(two); 

    Collections.sort(one); 
    Collections.sort(two);  
    return one.equals(two); 
} 
+0

Как переопределить метод equals? –

+0

Но для подтверждения еще раз вам действительно нужен ArrayList как ключ? – Sam

0

Я не знаю, почему вам нужен список в качестве ключа и строку в качестве значения, но вы в основном используете один и тот же «ключ» для каждого положить поскольку хэш-код является одинаковым для любого пустого списка. Как и другие ответы, лучше всего переключить список как значение и строку в качестве ключа. При изменении списка, любые будущие попытки .get возвратит нуль

public static void main(String...args) { 
     Map<List<String>, String> test = new HashMap<List<String>, String>(); 
     List<String> bob = new ArrayList<>(); 
     bob.add("asdf"); 
     test.put(new ArrayList<String>(), "s1"); 
     test.put(bob, "s2"); 

     System.out.println(test.size()); 
     System.out.println(test.get(bob)); 
    } 

выходы

2 
s2 

Когда новый элемент добавляется как

public static void main(String...args) { 
     Map<List<String>, String> test = new HashMap<List<String>, String>(); 
     List<String> bob = new ArrayList<>(); 
     bob.add("asdf"); 
     test.put(new ArrayList<String>(), "s1"); 
     test.put(bob, "s2");  
     bob.add("aabbcc"); 

     System.out.println(test.size()); 
     System.out.println(test.get(bob)); 
    } 

ГЭТ не будет работать, так как хэш списка изменился. Выходной сигнал в этом случае будет:

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