object==object,不比较引用
object==object, doesn't comparing reference
我已经覆盖了哈希码和等于找到具有相同开始日期和结束日期的值。而且我得到了重复对象的类似哈希码。当等同于这些对象时,我得到布尔值 "false"。在我的理解中,object==object 比较对象的引用,即使引用相同;代码返回 false。你能帮我理解问题是什么吗?我在下面发布了我的代码:
哈希码和等于方法
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.startDate == null) ? 0 : this.startDate.getDate());
result = prime * result + ((this.closingDate == null) ? 0 : this.closingDate.getDate());
return result;
}
public boolean equals(Object customer) {
if(customer == null || customer.getClass()!= this.getClass())
return false;
return this==customer;
}
Main.java
public class HashQuestion {
public static void main(String[]args) {
Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
custMap.put(1, createCustomer(1, new Date()));
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));
Customer checkCustomer = createCustomer(1, new Date());
for (Customer cust : custMap.values()) {
if (cust.equals(checkCustomer)) {
System.out.println("Duplicate No: "+cust.getCustId()+ ", Start date: " +
cust.getStartDate().toString() + " End date: " +cust.getClosingDate().toString());
}
else
System.out.println("No: "+cust.getCustId()+ ", Start date: " +
cust.getStartDate().toString() + " End date: " +cust.getClosingDate().toString());
}
}
@SuppressWarnings("deprecation")
static Customer createCustomer(int number, Date date) {
Date closeDate = new Date();
Date startDate = new Date();
closeDate.setDate(date.getDate() + number);
startDate.setDate(date.getDate() - number);
return new Customer(number, number+1, startDate, closeDate);
}
}
输出:
No: 1, Start date: Wed Jun 20 19:42:46 IST 2018 End date: Fri Jun 22 19:42:46 IST 2018
No: 2, Start date: Tue Jun 19 19:42:46 IST 2018 End date: Sat Jun 23 19:42:46 IST 2018
No: 3, Start date: Mon Jun 18 19:42:46 IST 2018 End date: Sun Jun 24 19:42:46 IST 2018
checkCustomer 对象引用:Customer@643
对象引用(在地图中):[Customer@643、Customer@625、Customer@607]
此处 object1 与 checkCustomer obj 具有相同的引用。然而 obj==checkCustomer, returns false。
由此变化:
Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
custMap.put(1, createCustomer(1, new Date()));
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));
Customer checkCustomer = createCustomer(1, new Date()); //This is a different reference
为此:
Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
Customer checkCustomer = createCustomer(1, new Date());
custMap.put(1, checkCustomer); //Now this is the same reference
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));
您正在创建 4 个不同的客户,这将创建三个。
您正在通过
创建两个不同的对象
return new Customer(number, number+1, startDate, closeDate);
所以比较必须是假的。如果你想比较对象的属性,你必须在你的 equals 方法中实现它。
应该看起来更像:
public boolean equals(Object customer) {
if(customer == null || customer.getClass()!= this.getClass())
return false;
return this.getCustId()==customer.getCustId();
}
如果您创建一个新对象(使用 "new"),这些对象在堆中将始终具有不同的地址,因此如果您比较它们,== 将始终 return 为假。
例如
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
i1.equals(i2) --> true
i1 == i2 --> false
在最后一行的 equals 方法中,您进行了引用比较 (==),您永远不应该在对象中这样做(仅限基元和枚举)。如果您使用的是 IDE(例如 eclipse),您可以使用标识对象实例的字段生成 equals 和 hashcode 方法。
所以让我把我的回答分成两部分:
(i) 对象引用如何评估为相同----
java.lang.Object提供了toString方法的实现,
returns 的字符串是 class 名称后跟“at”符号 (@) 和哈希码的无符号十六进制表示形式,例如 。在你的情况下
检查客户对象参考:Customer@643
对象引用(在地图中):[Customer@643, Customer@625, Customer@607]
映射中的第一个元素和检查引用是完全不同的对象,但 toString() 方法将它们计算为相同是因为散列冲突,而您的自定义 hashCode() 方法对此有所贡献,
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.startDate == null) ? 0 : this.startDate.getDate());
result = prime * result + ((this.closingDate == null) ? 0 : this.closingDate.getDate());
return result;
}
这完全没问题,因为没有冲突就没有散列函数存在
2) 即使引用相同为什么你的 equals(Object o) 实现没有 return true ---
让我们检查一下您的 equals 方法:
public boolean equals(Object customer) {
if(customer == null || customer.getClass()!= this.getClass())
return false;
return this==customer;
}
请注意“==”运算符检查两个引用是否指向同一个对象。在您的情况下,它不是 returned false 。
PS:根据经验,请考虑覆盖 toString() 方法。检查 EffectiveJava 第二版中的文章 Item10。
根据我对这个问题的分析,“==”比较的是内存地址,而不是对象引用。以下 Whosebug 问题有助于我理解这一点:
What is the difference between == vs equals() in Java?
Memory address of variables in Java
理解有误请告诉我
谢谢大家
我已经覆盖了哈希码和等于找到具有相同开始日期和结束日期的值。而且我得到了重复对象的类似哈希码。当等同于这些对象时,我得到布尔值 "false"。在我的理解中,object==object 比较对象的引用,即使引用相同;代码返回 false。你能帮我理解问题是什么吗?我在下面发布了我的代码:
哈希码和等于方法
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.startDate == null) ? 0 : this.startDate.getDate());
result = prime * result + ((this.closingDate == null) ? 0 : this.closingDate.getDate());
return result;
}
public boolean equals(Object customer) {
if(customer == null || customer.getClass()!= this.getClass())
return false;
return this==customer;
}
Main.java
public class HashQuestion {
public static void main(String[]args) {
Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
custMap.put(1, createCustomer(1, new Date()));
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));
Customer checkCustomer = createCustomer(1, new Date());
for (Customer cust : custMap.values()) {
if (cust.equals(checkCustomer)) {
System.out.println("Duplicate No: "+cust.getCustId()+ ", Start date: " +
cust.getStartDate().toString() + " End date: " +cust.getClosingDate().toString());
}
else
System.out.println("No: "+cust.getCustId()+ ", Start date: " +
cust.getStartDate().toString() + " End date: " +cust.getClosingDate().toString());
}
}
@SuppressWarnings("deprecation")
static Customer createCustomer(int number, Date date) {
Date closeDate = new Date();
Date startDate = new Date();
closeDate.setDate(date.getDate() + number);
startDate.setDate(date.getDate() - number);
return new Customer(number, number+1, startDate, closeDate);
}
}
输出:
No: 1, Start date: Wed Jun 20 19:42:46 IST 2018 End date: Fri Jun 22 19:42:46 IST 2018
No: 2, Start date: Tue Jun 19 19:42:46 IST 2018 End date: Sat Jun 23 19:42:46 IST 2018
No: 3, Start date: Mon Jun 18 19:42:46 IST 2018 End date: Sun Jun 24 19:42:46 IST 2018
checkCustomer 对象引用:Customer@643
对象引用(在地图中):[Customer@643、Customer@625、Customer@607]
此处 object1 与 checkCustomer obj 具有相同的引用。然而 obj==checkCustomer, returns false。
由此变化:
Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
custMap.put(1, createCustomer(1, new Date()));
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));
Customer checkCustomer = createCustomer(1, new Date()); //This is a different reference
为此:
Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
Customer checkCustomer = createCustomer(1, new Date());
custMap.put(1, checkCustomer); //Now this is the same reference
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));
您正在创建 4 个不同的客户,这将创建三个。
您正在通过
创建两个不同的对象return new Customer(number, number+1, startDate, closeDate);
所以比较必须是假的。如果你想比较对象的属性,你必须在你的 equals 方法中实现它。
应该看起来更像:
public boolean equals(Object customer) {
if(customer == null || customer.getClass()!= this.getClass())
return false;
return this.getCustId()==customer.getCustId();
}
如果您创建一个新对象(使用 "new"),这些对象在堆中将始终具有不同的地址,因此如果您比较它们,== 将始终 return 为假。
例如
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
i1.equals(i2) --> true
i1 == i2 --> false
在最后一行的 equals 方法中,您进行了引用比较 (==),您永远不应该在对象中这样做(仅限基元和枚举)。如果您使用的是 IDE(例如 eclipse),您可以使用标识对象实例的字段生成 equals 和 hashcode 方法。
所以让我把我的回答分成两部分:
(i) 对象引用如何评估为相同---- java.lang.Object提供了toString方法的实现, returns 的字符串是 class 名称后跟“at”符号 (@) 和哈希码的无符号十六进制表示形式,例如 。在你的情况下 检查客户对象参考:Customer@643 对象引用(在地图中):[Customer@643, Customer@625, Customer@607]
映射中的第一个元素和检查引用是完全不同的对象,但 toString() 方法将它们计算为相同是因为散列冲突,而您的自定义 hashCode() 方法对此有所贡献,
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.startDate == null) ? 0 : this.startDate.getDate());
result = prime * result + ((this.closingDate == null) ? 0 : this.closingDate.getDate());
return result;
}
这完全没问题,因为没有冲突就没有散列函数存在
2) 即使引用相同为什么你的 equals(Object o) 实现没有 return true ---
让我们检查一下您的 equals 方法:
public boolean equals(Object customer) {
if(customer == null || customer.getClass()!= this.getClass())
return false;
return this==customer;
}
请注意“==”运算符检查两个引用是否指向同一个对象。在您的情况下,它不是 returned false 。
PS:根据经验,请考虑覆盖 toString() 方法。检查 EffectiveJava 第二版中的文章 Item10。
根据我对这个问题的分析,“==”比较的是内存地址,而不是对象引用。以下 Whosebug 问题有助于我理解这一点:
What is the difference between == vs equals() in Java?
Memory address of variables in Java
理解有误请告诉我
谢谢大家