简体   繁体   中英

Why hashTable contains redundant Keys

I have a problem with Hashtable; it contains redundant keys. I have redefined the equal and the hashcode, but the same problem. below is an example of my problem. I'm really need help. Thank you in advance.

public class Payoff {
    public ArrayList<Cluster> coalitions = new ArrayList<Cluster>();

    @Override
    public boolean equals(Object t) {
        // Vérification de la référence
        if (t==this)
            return true;
        //Vérification du type du paramètre puis de ses attributs.
        if (t instanceof Payoff) {
            Payoff tbis = (Payoff)t;
            return this.coalitions.equals(tbis.coalitions);
        } else
            return false;
    }

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

public class Cluster implements Cloneable {
    public ArrayList<Integer> dataArray = new ArrayList<Integer>();
    public double[] ch;
    public double coalitionPayoff;

    public Cluster() {
    }

    public Cluster(Cluster obj) {
        this.ch = obj.ch;
        this.dataArray = (ArrayList<Integer>)obj.dataArray.clone();
        this.coalitionPayoff = obj.coalitionPayoff;
    }

    public boolean equals(Object T)
{   // Vérification de la référence
    if (T==this)
        return true;
    //Vérification du type du paramètre puis de ses attributs.
    if (T instanceof Cluster)
    {
        Cluster Tbis = (Cluster) T;
        return this.DataArray.equals(Tbis. DataArray) && Arrays.equals(this.Ch,Tbis.Ch)
                 && (this.CoalitionPayoff ==Tbis.CoalitionPayoff);

    } else
        return false;
}

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((dataArray == null) ? 0 : dataArray.hashCode());
        //result = prime * result + (int) (coalitionPayoff ^ (coalitionPayoff >>> 32));
        result = prime * result + ((ch == null) ? 0 : ch.hashCode());
        return result;
    }

    public Cluster clone() {
        return new Cluster ();
    }
}

public static void main(String[] args) throws Exception {
    Hashtable<Payoff,Double> HashTab = new Hashtable<Payoff,Double>();
    Payoff Pay1 = new Payoff();
    Cluster Cluster1 = new Cluster();
    Cluster1.DataArray.addAll(java.util.Arrays.asList(1,2,3));
    double[] ary = {1.5};
    Cluster1.Ch=  ary;
    Pay1.Coalitions.add(Cluster1);
    Cluster1 = new Cluster();
    Cluster1.DataArray.addAll(java.util.Arrays.asList(4,5));
    double[] ary2 = {4.5};
    Cluster1.Ch=  ary2;
    Pay1.Coalitions.add(Cluster1);
    HashTab.put(Pay1, 0.5);

    Payoff Pay2 = new Payoff();
    Cluster Cluster2 = new Cluster();
    Cluster2.DataArray.addAll(java.util.Arrays.asList(1,2,3));
    double[] ary3 = {1.5};      Cluster2.Ch=  ary3;
    Pay2.Coalitions.add(Cluster2);
    Cluster2 = new Cluster();
    Cluster2.DataArray.addAll(java.util.Arrays.asList(4,5));
    double[] ary4 = {4.5};
    Cluster2.Ch=  ary4;
    Pay2.Coalitions.add(Cluster2);
   if(!HashTab.containsKey(Pay2)){
      HashTab.put(Pay2, 0.5);
    }
    System.out.println(HashTab.size());
}

This line is the problem:

result = prime * result + ((ch == null) ? 0 : ch.hashCode()

This is the hashcode of the array not the hashcode of the content of the array, hence when you say:

double[] ary = {1.5};
double[] ary3 = {1.5};

it is different besides having the same data in it. Make sure you use the content, not the object reference as hashcode.

And of course Java has a solution for that:

result = prime * result + ((ch == null) ? 0 : Arrays.hashCode(ch)

Update

And this is my test code I used for approaching the problem. JUnit rulez!

public class TestHashTable
{
    @Test
    public void testEmpty()
    {
        final Cluster c1 = new Cluster();
        final Cluster c2 = new Cluster();
        Assert.assertEquals(c1, c2);
        Assert.assertEquals(c1.hashCode(), c2.hashCode());
    }

    @Test
    public void testSame()
    {
        final Payoff pay1 = new Payoff();
        final Cluster cluster1 = new Cluster();
        cluster1.dataArray.addAll(java.util.Arrays.asList(1,2,3));
        pay1.coalitions.add(cluster1);

        Assert.assertEquals(pay1, pay1);
        Assert.assertEquals(pay1.hashCode(), pay1.hashCode());
    }   

    @Test
    public void testEquals()
    {
        final Payoff pay1 = new Payoff();
        final Cluster cluster1 = new Cluster();
        cluster1.dataArray.addAll(java.util.Arrays.asList(1,2,3));
        pay1.coalitions.add(cluster1);

        final Payoff pay2 = new Payoff();
        final Cluster cluster2 = new Cluster();
        cluster2.dataArray.addAll(java.util.Arrays.asList(1,2,3));
        pay2.coalitions.add(cluster2);

        Assert.assertEquals(cluster1, cluster2);
        Assert.assertEquals(pay1, pay2);

        Assert.assertEquals(cluster1.hashCode(), cluster2.hashCode());
        Assert.assertEquals(pay1.hashCode(), pay1.hashCode());
    }

    @Test
    public void testUseInMap()
    {
        final Payoff pay1 = new Payoff();
        final Cluster cluster1 = new Cluster();
        cluster1.dataArray.addAll(java.util.Arrays.asList(1,2,3));
        final double[] a1 = {1.5};
        cluster1.ch = a1;
        pay1.coalitions.add(cluster1);

        final Payoff pay2 = new Payoff();
        final Cluster cluster2 = new Cluster();
        final double[] a2 = {1.5};
        cluster2.ch = a2;
        cluster2.dataArray.addAll(java.util.Arrays.asList(1,2,3));
        pay2.coalitions.add(cluster2);

        final Map<Payoff, Double> map = new HashMap<Payoff, Double>();
        map.put(pay1, 1.0);
        map.put(pay2, 2.0);

        Assert.assertEquals(1, map.size());
        Assert.assertTrue(2.0 == map.get(pay1));
    }
}

The equals method of Cluster returns false because this.ch.equals(tbis.ch) returns false.

array1.equals(array2) is equal to array1 == array2 , so if the content is the same but the actual array instance is different, the method will return false. To check the content of the arrays rather than the array instance, use Arrays.equals(array1,array2) (or in your case: Arrays.equals(this.ch,tbis.ch) ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM