2

所以,我想制作一个字符串列表到字符串的映射,但我无法让它正常工作:

这是我所做的所有代码,在我找出原因之前,我无法进步:

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 次调用时只添加了一个对象?我知道不小心将同一个对象添加到集合中的危险,但我专门为每个 put 创建了一个新的 ArrayList,从而创建了一个全新的对象。

那么为什么 Map 中只有一个对象呢?谢谢!

4

5 回答 5

3

ArrayList#hashCode() 为所有这些返回相同的值。如果您查看它的来源:http: //grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/AbstractList.java#AbstractList.hashCode%28 %29

您可以看到,如果没有元素或所有元素相同,则 hashCode 将相同。

修复它,它应该可以正常工作。使用 Map 或以一种或另一种方式更改 hashCode。

于 2013-02-12T05:24:00.480 回答
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)。因此,您的Map.

另请注意:

public Object put(Object key, Object value) 将指定值与此映射中的指定键相关联。如果映射先前包含此键的映射,则替换旧值。

这就是您得到 1 而不是 3 的原因,因为您添加了相同的 object new ArrayList<String>()

更详细地了解 Class HashM规范。

于 2013-02-12T05:26:22.580 回答
1

您使用 ArrayList 作为键,尝试

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

它打印

true
于 2013-02-12T05:27:33.053 回答
0

我不知道为什么你需要列表作为键和字符串作为值,但你基本上对每个 put 操作使用相同的“键”,因为哈希码对于任何空列表都是相同的。就像提到的其他答案一样,最好将列表切换为值,将字符串切换为键。如果列表发生变化,任何未来的 .get 尝试都将返回 null

   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));
   }

get 将不起作用,因为列表的哈希已更改。在这种情况下,输出将是:

2
null
于 2013-02-12T06:00:57.207 回答
0

最好的方法是使用 String 对象作为键,使用 List 作为值。

看看 java 文档在这里说了什么。

如果您想将 ArrayList 添加为键,那么覆盖 equals 方法就足够了。

这里的帖子提供了很好的见解。我从那篇文章中放了一些我喜欢的东西。

覆盖两个 ArrayList 的等于:

 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);
}
于 2013-02-12T05:38:53.327 回答