2

i'm trying to build a HashMap having two keys in this way: first i created a class which is only a data structure.

public class Tarta {
    public String nome;
    public String data;

    public Tarta(String nome, String data) {
        this.nome = nome;
        this.data = data;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}

Then i populated my map by writing this in another class:

mappaTarta.put(new Tarta(nome, data), peso);

During compilation i had no errors, but when testing i got null, for example:

System.out.println(lr.leggiRecord().get(new Tarta("R", "15/11/2015")));

Can you kindly explain me why? Thankyou

2
  • 9
    You need to override hashCode and equals. Commented Dec 11, 2015 at 15:03
  • And if you want to support TreeMap too, you must implement Comparable. Commented Dec 11, 2015 at 15:05

2 Answers 2

13

If you want to use items as keys in a HashMap, you need to override their equals and hashCode methods. Otherwise, the default implementations will consider two instances created with identical parameters as different, because they are two different instances.

Currently:

Tarta a = new Tarta("foo", "bar");
Tarta b = new Tarta("foo", "bar");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // false
System.out.println(a.hashCode() == b.hashCode()); // false

Example implementations:

@Override public boolean equals(Object other) {
  if (other == this) return true;
  if (other instanceof Tarta) {
    Tarta that = (Tarta) other;
    return Objects.equals(this.name, that.name)
        && Objects.equals(this.data, that.data);
  }
  return false;
}

@Override public int hashCode() {
  return Objects.hash(name, data);
}

Then:

Tarta a = new Tarta("foo", "bar");
Tarta b = new Tarta("foo", "bar");
System.out.println(a == b); // false - they are still different instances
System.out.println(a.equals(b)); // true
System.out.println(a.hashCode() == b.hashCode()); // true

Note that it is also advisable only to use immutable objects as keys in HashMaps: you should make name and data final at the very least, and make the class final too to make it truly immutable.

Sign up to request clarification or add additional context in comments.

6 Comments

I agree about the class being immutable. I think it is more than advisable; it should be mandatory.
I don't understand... so why my code was wrong? Because i'm pretty sure i can write HashMap<Integer, Object> xyz = new HashMap<>();, so, if i can use a "double value" or "multiple value", why can't i use a multiple key, as i posted before?
The value is completely irrelevant here: only the key matters. Think about how a HashMap works internally: it places things in a bucket according to the hash code of the key. If you put something in with one hash code, and then ask for something with a different hash code, it is going to look in the wrong bucket and say it didn't find your key, and so doesn't give you the value you expected back. (This is why you need to override hashCode)
And then, if you have not overridden equals, it might look in the correct hash bin and find multiple items. So, it needs to go through each of them saying "is your key equal to the get key?", which it does using equals. If you've not overridden equals, it won't think that the keys are equal, so it won't return you a value.
You can use Integer as a map key because it correctly overrides equals and hashCode (and it's immutable too).
|
0

Java VM uses the Object.hashCode() and Object.equals(Object) to compare object so basicaly it dont know how to compare the Tarta Object and you need to override those methods i mentioned to work! Sory about my english

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.