java 为什么要重写equals()和hashcode()

Java equals与hashcode重写
探讨了在Java中为何必须为自定义类重写equals()和hashcode()方法,尤其是在使用集合类的.contains()方法时,以确保正确判断元素相等性。

为什么要重写equals()和hashcode()

在java里集合类是使用十分频繁的数据类型,Collection类中定义了一个方法是.contains(),不知道小伙伴们是否遇到过使用.contains()一直返回false,明明某个元素就在集合中的情况,反正我是遇到了。。。

那为什么会出现这种情况呢?其实Collection实现contains方法是通过调用equals()来将参数和集合中的每个元素进行比较的。那么问题来了,对于我们自己写的可变类型的类,若没用重写equals方法的话,就会出问题。看下面这个例子:

class Vertex{
private String name;
 public Vertex(String vertex) {
  name = vertex;
 }
 public void setName(String cString) {
  name = cString;
 }
 public String getName() {
  return name;
 }
}

public static void main(String[] args)
 {
  String nString = "hhhh";
  Vertex vertex = new Vertex(nString);
  Vertex vertex2 = new Vertex(nString);
  if ( vertex.equals(vertex2))
   System.out.println("true");
  else {
   System.out.println("false");
  }
  vertex2.setName("hhhhh");
  if ( vertex.equals(vertex2))
   System.out.println("true");
  else {
   System.out.println("false");
  }
}

上述代码运行的结果按道理来说应该是true和false对吧,但其实是false和false。

在这里插入图片描述
那好,我们对class Vertex作出修改,重写它的equals()和hashcode()方法,想偷懒的同学也可以用eclipse自动生成,但要确保满足等价性,也就是对称,自反,传递。生成方法也是右键source–>Generate equals() and hashcode(),变成如下这样,也就是加上了equals和hashcode以后:

class Vertex{
private String name;
 public Vertex(String vertex) {
  name = vertex;
 }
 public void setName(String cString) {
  name = cString;
 }
 public String getName() {
  return name;
 }
 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  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;
  Vertex other = (Vertex) obj;
  if (name == null) {
   if (other.name != null)
    return false;
  } else if (!name.equals(other.name))
   return false;
  return true;
 }
}

然后我们在运行,这时候打印输出才是true和false了。

所以,如果你要用contains()方法,就必须得重写equals和hashcode,这里我只是举例个例子,想了解更多的小伙伴可以去找其他博客看看或者直接看collection的接口方法的实现。

<think>好的,我现在要回答用户关于Java实体类是否需要重写equalshashCode方法的问题。首先,我需要回顾一下这两个方法的作用以及它们在Java中的重要性。 根据用户提供的引用,比如引用[2]提到,当equals方法被重写时,hashCode也必须被重写。这是因为在Java中,如果两个对象相等(根据equals方法),它们的hashCode必须相同。如果不遵循这个规则,可能会导致在使用哈希表相关的集合类(如HashMap、HashSet)时出现错误。例如,两个对象在equals时相等但hashCode不同,存入HashSet会被视为不同的对象,导致重复元素被错误地存储。 接下来,我需要考虑用户提到的实体类的情况。实体类通常用于表示业务数据,可能会被存储到集合中或者需要进行比较。如果实体类没有重写equalshashCode,它们会继承Object类中的实现。Object的equals方法比较的是对象地址,而hashCode返回的是对象的地址转换的整数。这意味着即使两个实体对象的属性值完全相同,如果它们是不同的实例,equals会返回false,hashCode也会不同。这显然不符合业务逻辑中需要根据属性值判断对象相等的需求。 引用[5]中的例子展示了如何根据类的属性来重写hashCodeequals,将四个属性组合成一个hash值。这说明在实体类中,通常需要根据对象的属性来判断相等性生成哈希码。例如,用户管理系统中,两个User对象如果id相同就应该被视为同一个用户,即使它们是不同的实例。 另外,引用[4]提到如果没有重写hashCode方法,会使用父类(Object)的hashCode,这可能不符合实际需求。例如,当对象被放入HashMap时,正确的hashCode实现能提高哈希表的性能,减少哈希冲突,同时保证正确性。 还需要考虑集合类的使用场景。比如,HashSet内部使用HashMap来存储元素,如果对象的hashCode不正确,可能导致无法正确找到存储的位置,从而影响contains、add等方法的正确性。同样,HashMap的键对象如果hashCode不一致,会导致无法正确检索值。 总结起来,用户的问题核心在于理解为什么实体类需要重写这两个方法。主要原因包括:确保对象在哈希集合中的正确行为,维护equalshashCode的契约,以及根据业务逻辑正确判断对象的相等性。同时,必须注意重写时两者需要同时重写,避免破坏Java的约定,导致不可预见的错误。</think>在Java实体类中是否需要重写$equals()$$hashCode()$方法,取决于具体使用场景。以下是分步说明: ### 一、必要性判断条件 1. **需要对象比较逻辑** 当需要根据对象属性(而非内存地址)判断相等性时,必须重写$equals()$$。例如: $$User\ u1 = new User(1,"Tom");\\ User\ u2 = new User(1,"Tom");$$ 默认$Object.equals()$会比较地址值$u1 == u2$,而实际业务需要ID相同即视为同一个用户[^4] 2. **涉及哈希集合操作** 若将对象作为$HashMap$键或存入$HashSet$,必须同时重写这两个方法。否则会导致: ```java Set<User> set = new HashSet<>(); set.add(u1); set.contains(u2); // 返回false(若未正确重写) ``` ### 二、必须同时重写的原因 1. **哈希契约约束** Java规范要求:若两个对象$equals()$为$true$,其$hashCode()$必须相同。反之不成立(哈希碰撞允许存在)[^2] 2. **数据结构兼容性** ```java Map<User, String> map = new HashMap<>(); map.put(u1, "data1"); map.get(u2); // 返回null(若hashCode重写) ``` 未正确实现时,哈希表无法通过键的哈希值定位到正确存储桶[^5] ### 三、实现规范示例 ```java @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return id == user.id && Objects.equals(name, user.name); } @Override public int hashCode() { return Objects.hash(id, name); // 组合关键属性生成哈希 } ``` ### 四、特殊场景例外 如果实体类**永远不会被用于哈希集合**,且**不需要自定义比较逻辑**,可以不重写。但这种情况在实际开发中极少出现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值