Reputation: 7381
I have a class called Language
, Language has a bunch of fields but i only want to use one field to be able to compare it with other Language objects. That field is called languageCode
and it is a string. I have automatically implemented equals and hashcode using the method generation tool of Intellij Idea. Heres the the class with the relevant field and the generated methods.
public class Language implements Serializable{
private String languageCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Language language = (Language) o;
return languageCode.equals(language.getLanguageCode());
}
@Override
public int hashCode() {
return Objects.hash(languageCode);
}
}
There is also another class called Journal
Journal also has a bunch of different fields but only one is relevant namely:
public class Journal {
private Map<Language, String> titleTranslations = new HashMap<>()
}
Through out the program i use the constant variable ENGLISH_LANGUAGE
which contains the english representing language object from the database. All the language objects in titleTranslations
are also coming from the same database table. Furthermore Journal definately has an english language object in its Hashmap titleTranslations.
However when i run the following test:
journal.getTitleTranslations().forEach((Language language, String string) ->{
log.info(language.getLanguageCode() + " " + string);
log.info("hashcode is " + language.hashCode());
});
log.info("default language " + ENGLISH_LANGUAGE.getLanguageCode());
log.info("hashcode is " + ENGLISH_LANGUAGE.hashCode());
log.info("contains key " + journal.getTitleTranslations().containsKey(ENGLISH_LANGUAGE));
log.info("key is not null " + (journal.getTitleTranslations().get(ENGLISH_LANGUAGE) != null));
It gives the following output:
de deutsch
hashcode is 3232
en english
hashcode is 3272
fr francais
hashcode is 3307
nl nederlands
hashcode is 3549
defautl language en
hashcode is 3272
contiains key false
key is not null false
and you can see that despite the hashcodes of ENGLISH_LANGUAGE and the english language object in titletranslations being exactly the same (3272) it still cannot find the key when using the get method and it returns false when i use containsKey
and using ENGLISH_LANGUAGE as argument.
Can someone please tell me what i'm doing wrong? Do single field hashcode implementations somehow don't work?
Thank you
Upvotes: 0
Views: 99
Reputation: 7381
Ok the problem appeared to be framework related. Because i am using a framework that uses proxy subclasses like hibernate the equals method should be adjusted slightly. This is something intellij can do for you automatically when you check the option Accept subclasses as parameter to equals() method
Below the checkbox is this explanation:
While generally incomplaint to Object.equals() specifiation accepting subclasses might be necessary for generated method to work correctly with frameworks, which generate Proxy subclasses like Hibernate
Checking this will create an equals method that uses this if statement if (!(o instanceof Language)) return false;
instead of this one if (o == null || getClass() != o.getClass()) return false;
.
This somehow fixes the problem. The hashcode method remains the same. Heres the full code:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Language)) return false;
Language language = (Language) o;
return getLanguageCode().equals(language.getLanguageCode());
}
@Override
public int hashCode() {
return Objects.hash(getLanguageCode());
}
Upvotes: 1