How should I implement hashCode() and equals() for the following class in Java?
class Emp
{
int empid ; // unique across all the departments
String name;
String dept_name ;
String code ; // unique for the department
}
in Eclipse right mouse click-> source -> generate hashCode() and equals() gives this:
/* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (code == null ? 0 : code.hashCode());
return result;
}
/* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Emp))
return false;
Emp other = (Emp) obj;
return code == null ? other.code == null : code.equals(other.code);
}
I've selected code as a unique field
try this code, use org.apache.commons.lang3.builder
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
append(empid).
append(name).
append(dept_name ).
append(code ).
toHashCode();
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
Emp rhs = (Emp) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
isEquals();
}
Guava has helper methods for creating them. You tell it which fields to take in consideration and it will handle nulls for you and do the prime number calculation for hashcode.
IDEs can also generate them based on the fields you choose.
The advantage of delegating it to a tool like that is you get a standard solution and will worry less about bugs and maintenance of varied implementations spread all over your project.
Here's an example of using Guava and generated by an IntelliJ plugin: https://plugins.jetbrains.com/plugin/7244?pr=
If code is unique (i.e. your business key), it's best to only use the code for equals and hashCode - it's good practice to seperate business key (code) from object id (id).
Here's a nice read: Hibernate Documentation: Equals and HashCode (valid not only for Hibernate itself)
what ever values you use in equals to determine if two objects are the same, are the the values that you need to use to create a hash code.
public boolean equals(Object o) {
boolean result = false;
if(o instanceof CategoryEnum) {
CategoryEnum ce = (CategoryEnum) o;
result = ce.toString().equals(name);
}
return result;
}
public int hashCode()
{
int hash = 6;
hash += 32 * name.hashCode();
return hash;
}
equals()and hashcode(),They have a lot of different places.
equals(),if we don't Override it from Object,it represent that whether two variables are pointing to the same object heap?
public Class Student(){
private int id;
private name;
public Student(int id,String name){
this.name=name;
this.id=id;
}
public void main(String[] args){
Student A=new Student(20,'Lily');
Student B=new Student(20,'Lily');
boolean flag=A.equals(B)//flag=flase;
/*
*Although they attribute the same, but they are two different objects, they point to different memory
*/
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (this.getClass() != obj.getClass()) {
return false;
}
Student s=(Student)obj;
return new Integer(this.id).equals(new Integer(s.id))&&this.name.equals(s.name);
}
/**
*Sometimes even though we Override the equals, but we still can not determine whether the *two objects the same,
*In the collection object, such as HashSet, this time we have to Override the hashoCode ()
*/
public int hashCode(){
return id + name.hashCode() ;
}
Related
Here is my application
public class testwithmain {
public static void main(String[]args)
{
Money m12CHF = new Money(12,"CHF");
System.out.println(m12CHF.amount());
Money m14CHF = new Money(14,"CHF");
System.out.println(m14CHF.amount());
Money expected = new Money(26,"CHF");
System.out.println("expected "+expected.amount()+expected.currency());
Money result = m12CHF.add(m14CHF);
System.out.println("result "+result.amount()+result.currency());
System.out.println(expected.equals(result));
}
}
//-------------------------
public class Money {
private int fAmount;
private String fCurrency;
public Money(int amount, String currency) {
fAmount = amount;
fCurrency = currency;
}
public int amount() {return fAmount;}
public String currency() {return fCurrency;}
public Money add(Money m) {
return new Money(amount() + m.amount(), currency());
}
}
The result is:
12
14
expected 26CHF
result 26CHF
false
Please, why i have false ?
Thank you so much.
Your Money class lacks an implementation of equals method, which is required in order for Java to know that the object representing the result of m12CHF.add(m14CHF) and the new Money(26,"CHF") represent the same thing, even though the two are distinct Java objects.
The code inside equals should follow this general template:
#Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Money)) {
return false;
}
Money other = (Money) o;
... // Your code goes here
}
#Override
public int hashCode() {
return Objects.hash(fAmount, fCurrency);
}
Your implementation needs to compare fAmount and fCurrency of your object to the values in other.fAmount and other.fCurrency. Use equals for comparison of String objects; numbers can be compared with == operators.
As Nexevis said you need to override the equals method (which is inherited from the object class)
#Override
public boolean equals(Object obj){
if(obj instanceof Money){
Money other = (Money)obj;
//now you define when two intance object of Money are equal...
}
//...
}
Why is this necessary?
Because the current equals that you are using it is the equals from the Object class. Object's equals method defines that two objects are the same when they have the same reference
It is common knowledge that when equals() is overridden, hashCode() must also be overridden.
This is a typical example of this in a non-JavaFX bean class.
public class Person {
private String name;
private int age;
#Override
public int hashCode() {
int result = 17;
result = 31 * result + name.hashCode();
result = 31 * result + age;
return result;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return Objects.equals(name, rhs.name) &&
age == rhs.age;
}
}
The JavaFX bean:
public class Person {
private StringProperty name;
private IntegerProperty age;
// Option A
#Override
public int hashCode() {
int result = 17;
result = 31 * result + name.hashCode();
result = 31 * result + age.hashCode();
return result;
}
// Option B
#Override
public int hashCode() {
int result = 17;
result = 31 * result + name.get().hashCode();
result = 31 * result + age.get().hashCode();
return result;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return Objects.equals(name.get(), rhs.name.get()) &&
Objects.equals(age.get(), rhs.age.get());
}
}
So which of the 2 methods is the correct way to write hashCode()? Or is the correct method something totally different?
Properties don't override hashCode and equals. You can verify this by going to their documentation page (for example StringProperty) and scrolling down to where it says "Methods inherited from class java.lang.Object". If hashCode and equals are listed, then they aren't overridden.
Because of that, name.get().hashCode() would be correct, for example. name.hashCode() would return the identity hash code defined by Object.
The same can be said for equals. For example, name.equals(rhs.name) would call the base implementation from Object, which is the same as name == rhs.name.
method hashCode() is to help computer know two objects is not equal quickly, two method you write above is ok.
if you use java 1.7+, you can use
Objects.hash(filed1,filed2,filed3,.....)
to simplify.
I am writing a comparable class. I have overridden compareTo method to sort my objects based on date in descending order.
public class Employee implements Comparable
{
private Timestamp joinDate;
public Timestamp getJoinDate()
{
return joinDate;
}
public void setJoinDate(Timestamp joinDate)
{
this.joinDate = joinDate;
}
#Override
public int compareTo(Employee a)
{
//sort employess based on join date desc
return a.getJoinDate().compareTo(this.getJoinDate());
}
}
My Sonar is complaing to override equals method.
How do I override equals method here.
If you want to override the method compareTo, you have to use the same signature. The actual signature uses an Object parameter:
#Override
public int compareTo(Object o)
{
return ((Employee) o).getJoinDate().compareTo(joinDate);
}
Note that you have to explicitly cast the object obj to Employee, otherwise you won't be able to call its method getJoinDate().
Edit: If you want to override the equals() method you can return the result of comparing the attributes joinDate:
#Override
public boolean equals(Object obj)
{
return joinDate.equals(((Employee) obj).getJoinDate());
}
Note: It's not necessary to call getJoinDate() inside the Employee class, so you can just do:
return ((Employee) o).joinDate.compareTo(joinDate);
or
return joinDate.equals(((Employee) obj).joinDate);
Include this on your class (when you override equals, you have to also override hashCode):
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((joinDate == null) ? 0 : joinDate.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Snippet other = (Snippet) obj;
if (joinDate == null) {
if (other.joinDate != null)
return false;
} else if (!joinDate.equals(other.joinDate))
return false;
return true;
}
There is a difference between what what is indicated by .equals() == true and .compareTo(...) == 0. equals() method is intended to check whether two objects are equal, while compareTo is intended to set a relation order between elements, whether one is greater then the other, other is greater then the first one, or none of this is applicable which is typically means that objects are equal.
Unless you have a very good reason, you should override both equals and compareTo. An example of very good reason is BigDecimal class where equals compares both value of the object and its scale, while compareTo compares only values.
For your case, I'd override equals() like this:
#Override
public int hashCode() {
return this.getJoinDate().hashCode();
}
#Override
public boolean equals(Object obj) {
//correct argument check
if (!(obj instanceof Employee)) {
return false;
}
//check nulls
if (obj == null) {
return false;
}
Employee other = (Employee) obj;
if (this.getJoinDate() == null) {
return other.getJoinDate() == null;
}
return this.getJoinDate().equals(other.getJoinDate());
}
I have a HashMap for storing objects:
private Map<T, U> fields = Collections.synchronizedMap(new HashMap<T, U>());
but, when trying to check existence of a key, containsKey method returns false.
equals and hashCode methods are implemented, but the key is not found.
When debugging a piece of code:
return fields.containsKey(bean) && fields.get(bean).isChecked();
I have:
bean.hashCode() = 1979946475
fields.keySet().iterator().next().hashCode() = 1979946475
bean.equals(fields.keySet().iterator().next())= true
fields.keySet().iterator().next().equals(bean) = true
but
fields.containsKey(bean) = false
What could cause such strange behavioure?
public class Address extends DtoImpl<Long, Long> implements Serializable{
<fields>
<getters and setters>
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + StringUtils.trimToEmpty(street).hashCode();
result = prime * result + StringUtils.trimToEmpty(town).hashCode();
result = prime * result + StringUtils.trimToEmpty(code).hashCode();
result = prime * result + ((country == null) ? 0 : country.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (!StringUtils.trimToEmpty(street).equals(StringUtils.trimToEmpty(other.getStreet())))
return false;
if (!StringUtils.trimToEmpty(town).equals(StringUtils.trimToEmpty(other.getTown())))
return false;
if (!StringUtils.trimToEmpty(code).equals(StringUtils.trimToEmpty(other.getCode())))
return false;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
return true;
}
}
You shall not modify the key after having inserted it in the map.
Edit : I found the extract of javadoc in Map :
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.
Example with a simple wrapper class:
public static class MyWrapper {
private int i;
public MyWrapper(int i) {
this.i = i;
}
public void setI(int i) {
this.i = i;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return i == ((MyWrapper) o).i;
}
#Override
public int hashCode() {
return i;
}
}
and the test :
public static void main(String[] args) throws Exception {
Map<MyWrapper, String> map = new HashMap<MyWrapper, String>();
MyWrapper wrapper = new MyWrapper(1);
map.put(wrapper, "hello");
System.out.println(map.containsKey(wrapper));
wrapper.setI(2);
System.out.println(map.containsKey(wrapper));
}
Output :
true
false
Note : If you dont override hashcode() then you will get true only
As Arnaud Denoyelle points out, modifying a key can have this effect. The reason is that containsKey cares about the key's bucket in the hash map, while the iterator doesn't. If the first key in your map --disregarding buckets -- just happens to be the one you want, then you can get the behavior you're seeing. If there's only one entry in the map, this is of course guaranteed.
Imagine a simple, two-bucket map:
[0: empty] [1: yourKeyValue]
The iterator goes like this:
iterate over all of the elements in bucket 0: there are none
iterate over all the elements in bucket 1: just the one yourKeyValue
The containsKey method, however, goes like this:
keyToFind has a hashCode() == 0, so let me look in bucket 0 (and only there). Oh, it's empty -- return false.
In fact, even if the key stays in the same bucket, you'll still have this problem! If you look at the implementation of HashMap, you'll see that each key-value pair is stored along with the key's hash code. When the map wants to check the stored key against an incoming one, it uses both this hashCode and the key's equals:
((k = e.key) == key || (key != null && key.equals(k))))
This is a nice optimization, since it means that keys with different hashCodes that happen to collide into the same bucket will be seen as non-equal very cheaply (just an int comparison). But it also means that changing the key -- which will not change the stored e.key field -- will break the map.
Debugging the java source code I realized that the method containsKey checks two things on the searched key against every element in the key set:
hashCode and equals; and it does it in that order.
It means that if obj1.hashCode() != obj2.hashCode(), it returns false (without evaluating obj1.equals(obj2). But, if obj1.hashCode() == obj2.hashCode(), then it returns obj1.equals(obj2)
You have to be sure that both methods -may be you have to override them- evaluate to true for your defined criteria.
Here is SSCCE for your issue bellow. It works like a charm and it couldn't be else, because your hashCode and equals methods seem to be autogenerated by IDE and they look fine.
So, the keyword is when debugging. Debug itself can harm your data. For example somewhere in debug window you set expression which changes your fields object or bean object. After that your other expressions will give you unexpected result.
Try to add all this checks inside your method from where you got return statement and print out their results.
import org.apache.commons.lang.StringUtils;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Q21600344 {
public static void main(String[] args) {
MapClass<Address, Checkable> mapClass = new MapClass<>();
mapClass.put(new Address("a", "b", "c", "d"), new Checkable() {
#Override
public boolean isChecked() {
return true;
}
});
System.out.println(mapClass.isChecked(new Address("a", "b", "c", "d")));
}
}
interface Checkable {
boolean isChecked();
}
class MapClass<T, U extends Checkable> {
private Map<T, U> fields = Collections.synchronizedMap(new HashMap<T, U>());
public boolean isChecked(T bean) {
return fields.containsKey(bean) && fields.get(bean).isChecked();
}
public void put(T t, U u) {
fields.put(t, u);
}
}
class Address implements Serializable {
private String street;
private String town;
private String code;
private String country;
Address(String street, String town, String code, String country) {
this.street = street;
this.town = town;
this.code = code;
this.country = country;
}
String getStreet() {
return street;
}
String getTown() {
return town;
}
String getCode() {
return code;
}
String getCountry() {
return country;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + StringUtils.trimToEmpty(street).hashCode();
result = prime * result + StringUtils.trimToEmpty(town).hashCode();
result = prime * result + StringUtils.trimToEmpty(code).hashCode();
result = prime * result + ((country == null) ? 0 : country.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (!StringUtils.trimToEmpty(street).equals(StringUtils.trimToEmpty(other.getStreet())))
return false;
if (!StringUtils.trimToEmpty(town).equals(StringUtils.trimToEmpty(other.getTown())))
return false;
if (!StringUtils.trimToEmpty(code).equals(StringUtils.trimToEmpty(other.getCode())))
return false;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
return true;
}
}
How to Store unique objects to avoid the duplicates in java Set?
For example
Consider Employee object which (Employee Id, name, salary....)
list of employee of objects need to add in the Set.
We need to restrict the Set for the duplicate elements which need to identify by the "Employee Id.
What are the best way's to do?
If you are using an implementation of a java.util.Set, it should not allow duplicates as long as your equals and hashCode methods are implemented properly. Not sure why you have hashmap and hashtable as tags on your question though. Maybe you should rephrase your question and add the code that gives you issues?
Edit: considering your edit:
If you use a Set, your Employee should have the following methods:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
Similarly to #Dirk, you can also use HashCodeBuilder and EqualsBuilder from org.apache.commons.
It would look like this:
#Override
public int hashCode() {
return new HashCodeBuilder()
.append(id)
.append(name)
.append(salary)
.toHashCode();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Employee) {
final Employee employee = (Employee) obj;
return new EqualsBuilder()
.append(id, employee.id)
.append(name, employee.name)
.append(salary, employee.salary)
.isEquals();
} else {
return false;
}
}
Set Stores unique object only
Eg:
Set set = new HashSet();
// Add elements to the set
set.add("a");//true
set.add("b");//true
set.add("c");//true
set.add("d");//true
set.add("a");//false
add will return false when you will try to store the object which is already in the Set