Java JVM背后的原因';s默认对象。HashCode()实现

Java JVM背后的原因';s默认对象。HashCode()实现,java,hash,hashcode,Java,Hash,Hashcode,我试图理解为什么JVM的默认实现不会为所有对象返回相同的hashcode()值 我编写了一个程序,其中我覆盖了equals(),但没有覆盖hashCode(),其后果是可怕的 HashSet正在添加两个对象,即使相等的对象相同 TreeSet正在抛出具有类似实现的异常 还有更多 如果默认的对象'shashCode()实现返回相同的int值,那么所有这些问题都可以避免 我理解他们关于hashcode()和equals()的大量书面和讨论,但我无法理解为什么默认情况下无法处理事情,这很容易出错,后果

我试图理解为什么JVM的默认实现不会为所有对象返回相同的
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),我理解并同意,但我在不知不觉中破坏了它……为什么默认实现不能或不应该