一、equals()和hashCode():
1、方法介绍:Object的equals和hashCode方法往往是成对出现的且保持一致。
//在Object类中有一个方法:
public native int hashCode();
该方法用native修饰,所以是一个本地方法,所谓本地方法就是非java代码,这个代码通常用c或c++写成,在java中可以去调用它。
调用这个方法会生成一个int型的整数,我们叫它哈希码,哈希码和调用它的对象地址和内容有关。
2、重要性:正确重写这两个方法非常重要。java中所有比较的原理都是基于equals和hashCode。
二、应用举例:
1、像String、包装类等都重写了equals()和hashCode()方法。
2、集合:如果T/K/V是自定义的,
(1)Set<T>去重复原理:T需要重写equals和hashCode方法才能实现去重;demo:
public class Person {
private String name;
private String sex;
//省略set、get方法
@Override
public String toString() {
return "Person [name=" + 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;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
测试:
public static void main(String[] args) {
Set<Person> set=new HashSet<>();
Person person=new Person();
person.setName("zs");
person.setSex("nv");
set.add(person);
person=new Person();
person.setName("zs");
person.setSex("nvhj");
set.add(person);
Iterator<Person> it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
只会输出一个对象。
(2)Map<K,V>:根据K去重,则K需要重写这两个方法:
说明:TreeMap把键值中需要比较的元素重写CompareTo方法,这其实也是一种变向的equals和hashCode;
实体类Person(没有正确重写equals和hashCode方法):
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
public static void main(String[] args) {
Map<Person, Integer> map=new HashMap<>();
Person person=new Person();
person.setName("zs");
map.put(person, 20);
person=new Person();
person.setName("zs");
map.put(person, 20);
//Person key=new Person();
//key.setName("zs");
System.out.println(map.size());
}
输出:2
而如果将Person类正确重写了equals和hashCode方法,再次编译输出1。
(3)集合的removeAll方法求差集,也是根据equals和hashCode去重;
(4)List、Set的contains和indexOf检索方法就是根据需要检索的元素的equals和hashCode方法。实际上,其他涉及到indexOf等检索和比较值是否相等的也都是要正确重写这两个方法。demo:
public class Employee {
private String empno;
private String name;
@Override
public String toString() {
return "Employee [empno=" + empno + ", name=" + name + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((empno == null) ? 0 : empno.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;
Employee other = (Employee) obj;
if (empno == null) {
if (other.empno != null)
return false;
} else if (!empno.equals(other.empno))
return false;
return true;
}
public String getEmpno() {
return empno;
}
public void setEmpno(String empno) {
this.empno = empno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
注意这个实体类只对empno进行了equals和hashcode方法编写。
public class Main {
public static void main(String[] args) {
ArrayList<Employee> list=new ArrayList<>();
Employee employee=new Employee();
employee.setEmpno("0001");
employee.setName("zs");
list.add(employee);
employee=new Employee();
employee.setEmpno("0002");
employee.setName("zs");
list.add(employee);
Employee employee1=new Employee();
employee1.setEmpno("0002");
employee1.setName("zsk");
int a=list.indexOf(employee1);
System.out.println(a);
System.out.println(list.contains(employee1));
}
}
输出:1 true。
如果把Employee实体类的name和empno同时进行equals和hashCode,则输出-1 false。