正确实现Map <myobject,arraylist <myobject>&gt; </myobject,arraylist <myobject>的方法

时间:2014-04-11 22:48:32

标签: java hashmap multimap

我在接受采访时被问到这个问题。使用Google GuavaMultiMap不是一种选择。 我有一个班级

public class Alpha
{
     String company;
     int local;
     String title;
}

我有这个类的许多实例(按数百万的顺序)。我需要处理它们,最后找到独特的和重复的。 e.g。

instance --> instance1, instance5, instance7 (instance1 has instance5 and instance7 as duplicates)
instance2 --> instance2 (no duplicates for instance 2)

我的代码工作正常

声明数据结构

HashMap<Alpha,ArrayList<Alpha>> hashmap = new HashMap<Alpha,ArrayList<Alpha>>();

添加实例

for (Alpha x : arr)
{
    ArrayList<Alpha> list = hashmap.get(x); ///<<<<---- doubt about this. comment#1
    if (list == null)
    {
        list = new ArrayList<Alpha>();
        hashmap.put(x, list);
    }
        list.add(x);
}

打印实例及其副本。

for (Alpha x : hashmap.keySet())
{
    ArrayList<Alpha> list = hashmap.get(x); //<<< doubt about this. comment#2
    System.out.println(x + "<---->");
    for(Alpha y : list)
    {
        System.out.print(y);
    }
    System.out.println();
}

问题:我的代码有效,但为什么?当我做hashmap.get(x);时(代码中的注释#1)。两个不同的实例可能具有相同的哈希码。在这种情况下,我将向同一个List添加2个不同的对象。

当我检索时,我应该得到一个包含2个不同实例的List。 (注释#2)当我遍历列表时,我应该看到至少一个不与密钥重复但仍然存在于列表中的实例。我没有。为什么?。我尝试从hashCode函数返回常量值,它工作正常。

如果您想查看我对equalshashCode的实施情况,请与我们联系。

奖金问题:有什么方法可以优化它?

编辑:

@Override
    public boolean equals(Object obj) {
        if (obj==null || obj.getClass()!=this.getClass())
            return false;
        if (obj==this)
            return true;
        Alpha guest = (Alpha)obj;
        return guest.getLocal()==this.getLocal()
                && guest.getCompany()  == this.getCompany()
                && guest.getTitle() == this.getTitle();
    }

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (title==null?0:title.hashCode());
    result = prime * result + local;
    result = prime * result + (company==null?0:company.hashCode());
    return result;
}

2 个答案:

答案 0 :(得分:3)

  

两个不同的实例可能具有相同的哈希码

是的,但hashCode方法用于标识存储元素的索引。两个或多个密钥可以具有相同的hashCode,但这也是使用equals进行评估的原因。

来自Map#containsKey javadoc:

  

如果此映射包含指定键的映射,则返回true。更正式的是,当且仅当此映射包含关键字k的映射(true)时才返回key==null ? k==null : key.equals(k)。 (最多可以有一个这样的映射。)


您当前代码的一些增强功能:

  • Code oriented to interfaces。使用Map并按HashMap对其进行实例化。与ListArrayList类似。
  • 通常使用String方法比较Objectequals==比较引用,equals比较Object中存储的数据,具体取决于此方法的实现。因此,请更改Alpha#equals中的代码:

    public boolean equals(Object obj) {
        if (obj==null || obj.getClass()!=this.getClass())
            return false;
        if (obj==this)
            return true;
        Alpha guest = (Alpha)obj;
        return guest.getLocal().equals(this.getLocal())
                && guest.getCompany().equals(this.getCompany())
                && guest.getTitle().equals(this.getTitle());
    }
    
  • 在成对浏览地图的所有元素时,请改用Map#entrySet,您可以保存 Map#get使用的时间(因为它应该是是O(1)你不会保存那么多,但它更好):

    for (Map.Entry<Alpha, List<Alpha>> entry : hashmap.keySet()) {
        List<Alpha> list = entry.getValuee();
        System.out.println(entry.getKey() + "<---->");
        for(Alpha y : list) {
            System.out.print(y);
        }
        System.out.println();
    }
    

答案 1 :(得分:1)

  

使用equalshashCode来解决碰撞状态。

步骤:

  • 首先根据hashCode()
  • 中的标题进行比较
  • 如果标题相同,则根据公司名称查看equals()以解决碰撞状态。

示例代码

class Alpha {
    String company;
    int local;
    String title;

    public Alpha(String company, int local, String title) {
        this.company = company;
        this.local = local;
        this.title = title;
    }

    @Override
    public int hashCode() {
        return title.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Alpha) {
            return this.company.equals(((Alpha) obj).company);
        }
        return false;
    }
}

...

Map<Alpha, ArrayList<Alpha>> hashmap = new HashMap<Alpha, ArrayList<Alpha>>();

hashmap.put(new Alpha("a", 1, "t1"), new ArrayList<Alpha>());
hashmap.put(new Alpha("b", 2, "t1"), new ArrayList<Alpha>());
hashmap.put(new Alpha("a", 3, "t1"), new ArrayList<Alpha>());

System.out.println("Size : "+hashmap.size());

输出

Size : 2