一、学习记录之hashCode函数覆写,hashCode覆写和变量有关导致修改变量前在Hash集合中存储的元素查找不到。
二、用示例说明查找不到的原因----和Hash结构集合存储元素有关,由于修改前后的hash码不同造成查找不到;谨记在覆写hashCode函数时一定尽可能避免hash值和变量产生关系,否则会有意想不到的异常发生。
1、员工类:--在该类中覆写了hashCode函数,并且hashCode值和年龄可修改变量有关系,如下:
@Override
public int hashCode() {
// TODO Auto-generated method stub
int employeeHashCode = super.hashCode() + age;
return employeeHashCode;
}
2、测试说明过程:
在employPositionMap中存了员工和员工职位映射,初始employeeJack年龄为28保存到employPositionMap中,修改年龄为26,再从employPositionMap集合中查询employeeJack,查询结果为null,但实际在employPositionMap中保存了employeeJack;原因是对象的hash码不一致,查找的位置不一样,用图1说明,可能初始存的位置为2,而查询位置为5,所以查不到想要的,或者即使巧合查到,也不一定是期望的值。具体代码如下:
1 | 2 | 3 | 4 | 5 | 6 | 7 |
图1 存储位置说明
运行效果如图2所示:由于查找前修改了和hashCode有关的变量,修改前可以查到,修改后查找期望对象失败,为null;如下图所示:
三、异常复现代码如下
1、Empolyee类:
/**
* 员工类,包含ID,姓名和年龄
* @author fengbin15
*/
public class Employee {
//员工ID
private int id;
//员工姓名
private String name;
//员工年龄
private int age;
/**
* 构造函数
* @param id
* @param name
* @param age
*/
public Employee(int id, String name, int age)
{
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
int employeeHashCode = super.hashCode() + age;
return employeeHashCode;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return super.equals(obj);
}
}
2、测试主类:
/**
* 复现hashCode覆写异常
* @author fengbin15
*/
public class HashCodeTest {
/**
* 测试主函数
* @param args
*/
public static void main(String[] args)
{
//员工职位映射表--------该用法比较特殊,但可能会由于特殊原因用到
Map<Employee, String> employPositionMap = new HashMap<Employee, String>();
//添加职员
Employee employeeMike = new Employee(20200401, "Mike", 25);
Employee employeeMary = new Employee(20200402, "Mary", 26);
Employee employeeJack = new Employee(20200403, "Jack", 28);
Employee employeeTom = new Employee(20200404, "Tom", 23);
Employee employeeLucy = new Employee(20200405, "Lucy", 21);
Employee employeeJim = new Employee(20200406, "Jim", 26);
Employee employeeDavid = new Employee(20200407, "David", 29);
employPositionMap.put(employeeMike, "Manager");
employPositionMap.put(employeeMary, "Staff");
employPositionMap.put(employeeJack, "Staff");
employPositionMap.put(employeeTom, "Staff");
employPositionMap.put(employeeLucy, "Staff");
employPositionMap.put(employeeJim, "Staff");
employPositionMap.put(employeeDavid, "Staff");
//修改前查找对象,可以查找到,如下:
String beforeFind = employPositionMap.get(employeeJack);
System.out.println("修改前查询:" + beforeFind);
//修改employeeJack职员的年龄------在职员的Employee对象的hashCode与年龄有关
employeeJack.setAge(26);
//在员工职位存储列表中查询jack的职位
String afterFind = employPositionMap.get(employeeJack);
System.out.println("修改后查询:" + afterFind);
}
}
以上为自己遇到的问题,记录下来,供参考;如有不合适的地方,欢迎指正,共同进步,谢谢!