Java JVM背后的原因';s默认对象。HashCode()实现
我试图理解为什么JVM的默认实现不会为所有对象返回相同的Java JVM背后的原因';s默认对象。HashCode()实现,java,hash,hashcode,Java,Hash,Hashcode,我试图理解为什么JVM的默认实现不会为所有对象返回相同的hashcode()值 我编写了一个程序,其中我覆盖了equals(),但没有覆盖hashCode(),其后果是可怕的 HashSet正在添加两个对象,即使相等的对象相同 TreeSet正在抛出具有类似实现的异常 还有更多 如果默认的对象'shashCode()实现返回相同的int值,那么所有这些问题都可以避免 我理解他们关于hashcode()和equals()的大量书面和讨论,但我无法理解为什么默认情况下无法处理事情,这很容易出错,后果
hashcode()
值
我编写了一个程序,其中我覆盖了equals()
,但没有覆盖hashCode()
,其后果是可怕的
HashSet
正在添加两个对象,即使相等的对象相同TreeSet
正在抛出具有类似实现的异常对象'shashCode()
实现返回相同的int值,那么所有这些问题都可以避免
我理解他们关于hashcode()和equals()的大量书面和讨论,但我无法理解为什么默认情况下无法处理事情,这很容易出错,后果可能非常糟糕和可怕
这是我的示例程序
import java.util.HashSet;
import java.util.Set;
public class HashcodeTest {
public static void main(String...strings ) {
Car car1 = new Car("honda", "red");
Car car2 = new Car("honda", "red");
Set<Car> set = new HashSet<Car>();
set.add(car1);
set.add(car2);
System.out.println("size of Set : "+set.size());
System.out.println("hashCode for car1 : "+car1.hashCode());
System.out.println("hashCode for car2 : "+car2.hashCode());
}
}
class Car{
private String name;
private String color;
public Car(String name, String color) {
super();
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Car other = (Car) obj;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
import java.util.HashSet;
导入java.util.Set;
公共类HashcodeTest{
公共静态void main(字符串…字符串){
Car car1=新车(“本田”、“红色”);
Car car2=新车(“本田”、“红色”);
Set=newhashset();
集合。添加(car1);
集合。添加(car2);
System.out.println(“集合大小:+Set.size());
System.out.println(“car1的hashCode:+car1.hashCode());
System.out.println(“car2的hashCode:+car2.hashCode());
}
}
班车{
私有字符串名称;
私有字符串颜色;
公共汽车(字符串名称、字符串颜色){
超级();
this.name=名称;
这个颜色=颜色;
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共字符串getColor(){
返回颜色;
}
公共void setColor(字符串颜色){
这个颜色=颜色;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj)
返回true;
if(obj==null)
返回false;
如果(getClass()!=obj.getClass())
返回false;
汽车其他=(汽车)obj;
如果(颜色==null){
if(other.color!=null)
返回false;
}else如果(!color.equals(other.color))
返回false;
if(name==null){
if(other.name!=null)
返回false;
}如果(!name.equals(other.name))
返回false;
返回true;
}
}
输出:
套装尺寸:2
car1的哈希代码:330932989
car2的哈希代码:8100393
你违反了合同
hashcode和equals的编写方式应确保当equals返回true时,这些对象具有相同的hashcode
如果重写equals,则必须提供正常工作的哈希代码
默认实现无法处理它,因为默认实现不知道哪些字段是重要的。而自动实现并不能以有效的方式完成,hashcode的功能是加速数据结构中的数据查找等操作,如果实现不当,则性能将受到影响。
只要是合理可行的,类对象定义的hashCode方法确实会为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现,但JavaTM编程语言不需要这种实现技术。)
从文件:
如果两个对象根据相等值相等(对象)
方法,然后对每个
这两个对象必须产生相同的整数结果
然后,如果重写equals()的行为方式,则还必须重写hashCode()
另外,来自equals()的文档-
请注意,通常需要重写哈希代码
方法,以便维护
hashCode方法的总合同,其中规定
相等的对象必须具有相等的哈希代码
从对象的javadoc中
类:
返回对象的哈希代码值。支持此方法是为了使用哈希表,例如HashMap提供的哈希表
因此,如果默认实现提供相同的散列,它就无法达到目的
对于默认实现,它不能假设所有类都是值类,因此doc的最后一句话:
只要是合理可行的,类对象定义的hashCode方法确实会为不同的对象返回不同的整数
似乎您想建议在默认情况下计算hashCode
,只需获取所有对象字段并使用一些公式组合它们的hashCode即可。这种做法是错误的,可能导致许多不愉快的情况。在您的情况下,它会起作用,因为您的对象非常简单。但现实生活中的物体要复杂得多。举几个例子:
- 对象连接到双链接列表中(每个对象都有
previous
和next
字段)。默认实现将如何计算哈希代码?如果它检查字段,它将以无限递归结束
- 好,假设我们可以检测无限递归。让我们看看单链表。在这种情况下,每个节点的hashCode应该从所有后续节点计算出来?如果此列表包含数百万个节点怎么办?要生成hashCode,应该检查所有这些参数吗
- 假设您有两个
HashSet
对象。第一个是这样创建的:
HashSet<Integer> a = new HashSet<>();
a.add(1);
HashSet a=newhashset();
a、 增加(1);
第二个是这样创建的:
HashSet<Integer> b = new HashSet<>();
for(int i=1; i<1000; i++) b.add(i);
for(int i=2; i<1000; i++) b.remove(i);
HashSet b=newhashset();
对于(inti=1;iYes),我理解并同意,但我在不知不觉中破坏了它……为什么默认实现不能或不应该