[英]How to write equals and hashCode methods in java for attribute that is a list of other attributes
I have a HashMap
where the key is a class and value is an integer. 我有一个
HashMap
,其中的键是一个类,值是一个整数。 I need to check if an object of the class already exists in the map. 我需要检查地图中是否已存在该类的对象。 I use
containsKey()
, but for some reason it does not work when I include attribute sideDish
in the equals()
and hashCode()
. 我使用
containsKey()
,但是由于某些原因,当我在equals()
和hashCode()
包含属性sideDish
时,它不起作用。 Here is my code for the classes: 这是我的课程代码:
OrderItem class: OrderItem类:
@ToString
@Entity
@Table(name="OrderItem")
public class OrderItem implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Getter @Setter
private Long id;
@ManyToOne
@Getter @Setter
private Food food;
@ManyToMany
@Getter @Setter
private List<SideDish> sideDishes;
public OrderItem() {}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((food == null) ? 0 : food.hashCode());
result = prime * result + ((sideDishes == null) ? 0 : sideDishes.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;
OrderItem other = (OrderItem) obj;
if (food == null) {
if (other.food != null)
return false;
} else if (!food.equals(other.food))
return false;
if (sideDishes == null) {
if (other.sideDishes != null)
return false;
} else if (!sideDishes.equals(other.sideDishes))
return false;
return true;
}
}
Food class: 食品类:
@ToString
@Entity
@Table(name="Food")
public class Food implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Getter @Setter
private Long id;
@Column(nullable = false, unique = true)
@NotNull(message = "Name cannot be null.")
@Getter @Setter
private String name;
@ManyToMany
@Getter @Setter
private List<SideDish> sidedishes;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((foodtype == null) ? 0 : foodtype.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.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;
Food other = (Food) obj;
if (foodtype == null) {
if (other.foodtype != null)
return false;
} else if (!foodtype.equals(other.foodtype))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
SideDish class: SideDish类:
@Entity
@ToString(exclude= {"id","dishtype"})
@Table(name="SideDish")
public class SideDish implements Serializable, Comparable<SideDish>{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Getter @Setter
private Long id;
@Getter @Setter
@Column(nullable = false, unique = true)
private String name;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.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;
SideDish other = (SideDish) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
For some reason, if I removethe sideDish
attribute from equals()
and hashCode()
in the OrderItem
class, it works perfectly. 出于某种原因,如果我从
OrderItem
类的equals()
和hashCode()
中sideDish
属性,则它可以正常工作。
But I also need sideDish
to be checked as part of the object identity. 但是我还需要将
sideDish
作为对象标识的一部分进行检查。
Here is how I use it: 这是我的用法:
HashMap<OrderItem, Integer> orderItemsToSend = new HashMap<OrderItem, Integer>();
for (Order order : orders) {
for (OrderItem orderItem : order.getOrderItems()) {
int numSimilarOrders = getNumOfSimilarOrders(orderItem, orders);
if(!orderItemsToSend.containsKey(orderItem)) {
orderItemsToSend.put(orderItem, numSimilarOrders);
}else {
System.out.println("Vec je dodat item koji isti kao: " + orderItem.getFood().getName());
}
}
}
In your OrderItem
class, both your hashCode()
and equals()
depend on the property List<SideDish> sideDishes
. 在
OrderItem
类中, hashCode()
和equals()
取决于属性List<SideDish> sideDishes
。
Thus, if sideDishes
changes, so does the hashCode()
(and so does equality). 因此,如果
sideDishes
更改,则hashCode()
sideDishes
更改(相等性sideDishes
更改)。
A HashMap
uses both hashCode()
and equals()
to store and find the object which is the key . HashMap
使用hashCode()
和equals()
来存储和查找作为key的对象。 It uses a concept called " hash buckets ". 它使用了一个称为“ 哈希桶 ”的概念。 If you put a key into a
HashMap
, and then the hashCode()
changes, that object will be in the wrong hash bucket, and you won't be able to find it again. 如果将密钥放入
HashMap
,然后hashCode()
更改,则该对象将位于错误的哈希存储桶中,并且您将无法再次找到它。
A key is something which is used for lookup purposes - that's what the word "key" means. 密钥是用于查找目的的东西,这就是“密钥”一词的含义。 An important quality of a key, whether in a database, or a hashmap, is immutability.
密钥的重要质量,无论是在数据库中还是在哈希图中,都是不可变性的。 So in Java, that means an object which changes its
hashCode()
makes for a bad key. 因此,在Java中,这意味着更改其
hashCode()
的对象将产生错误的密钥。
It's a bit like if a file system did lookups by the hash of the filename, but then you changed the filename, but it didn't update the hash. 这有点像文件系统通过文件名的哈希进行查找,但是随后您更改了文件名,但没有更新哈希。 You'd only find the file by doing a lookup with the old name.
您只能通过使用旧名称进行查找来找到文件。
This simple test program will illustrate the point. 这个简单的测试程序将说明这一点。
We store 2 objects in a HashMap
, and then change the hashCode()
. 我们将2个对象存储在
HashMap
,然后更改hashCode()
。 The map still contains both objects, but now one of them cannot be found or used for lookup. 映射仍然包含两个对象,但是现在找不到其中之一或将其用于查找。
The solution is use some simple immutable object as the key , such as a Long
of its database ID. 解决方案是使用一些简单的不可变对象作为键 ,例如其数据库ID的
Long
。
Sample output is below the code. 示例输出在代码下方。
public class HashTest {
static class Hashable {
String name;
@Override
public int hashCode() {
return ((name == null) ? 0 : name.hashCode());
}
@Override
public boolean equals(Object object) {
return (object instanceof Hashable) && equals((Hashable) object);
}
private boolean equals(Hashable that) {
return Objects.equals(this.name, that.name);
}
@Override
public String toString() {
// Use identityHashCode() so we can really see which object is which
return "[" + name + ":" + System.identityHashCode(this) + "]";
}
}
public static void main(String[] args) {
Hashable one = new Hashable();
one.name = "one";
Hashable two = new Hashable();
two.name = "one";
print(one, two);
two.name = "two";
print(one, two);
HashMap<Hashable, Integer> map = new HashMap<>();
map.put(one, 1);
map.put(two, 2);
find(map, one, two);
one.name = "two"; // Let's confuse things
print(one, two);
find(map, one, two);
}
private static void print(Hashable one, Hashable two) {
System.out.print("Names:" + one.name + ":" + two.name);
System.out.print("\tHashcodes:" + one.hashCode() + ":" + two.hashCode());
System.out.println("\tEquals:" + one.equals(two));
}
private static void find(HashMap<Hashable, Integer> map, Hashable one, Hashable two) {
System.out.print(map);
System.out.print("\tFound: " + map.get(one));
System.out.println("\tFound: " + map.get(two));
}
}
Sample output: 样本输出:
Names:one:one Hashcodes:110182:110182 Equals:true
Names:one:two Hashcodes:110182:115276 Equals:false
{[one:366712642]=1, [two:1829164700]=2} Found: 1 Found: 2
Names:two:two Hashcodes:115276:115276 Equals:true
{[two:366712642]=1, [two:1829164700]=2} Found: 2 Found: 2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.