Java基础系列(十八):Object类(下)

Hash Code

在Java中,hash code(散列码)是由对象导出的一个整型值,以下是几个常见哈希值的算法:

1)Object类的 hashCode().返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。

2)String类的 hashCode().根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。

3)Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如 Integeri1=newInteger(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。

散列码的作用是作为散列表的key,我们会在后续的集合章节中详细的讲解,我们现在只需要知道,散列的价值在于速度。

Equals 和 Hashcode

这两个其实确切意义上并没有什么联系,前提是我们不会在HashSet,HashMap这种本质是散列表的数据结构中使用,如果我们要在HashSet,HashMap这种本质是散列表的数据结构中使用,在重写equals方法的同时也要重写hashCode方法,以便用户将对象插入到散列表中,否则会导致数据不唯一,内存泄漏等各种问题,具体的缘由会在集合源码分析中进行进一步的探讨。

总结:

1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。

2. equals()hashCode()需要同时覆盖,而且定义必须一致,也就是说equals比较了哪些域,hashCode就会对哪些域进行hash值的处理。

3.若两个对象 equals()返回true,则 hashCode()有必要也返回相同的值。

4.若两个对象 equals()返回false,则 hashCode()不一定返回不同的值。

5.若两个对象 hashCode()返回相同的值,则 equals()不一定返回true。

6.若两个对象 hashCode()返回不同值,则 equals()一定返回false。

7.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。

toString 方法

toString方法用于返回表示对象值的字符串,toString方法一般会被重写,重写的格式一般是:类名,然后是一对方括号括起来的域值。

在日常的编程中,我们应该给每一个自定义的类都添加一个toString方法,这样做有助于团队协作和代码的可读性。

例子

下面我们通过一个例子来看看如果重写Object类的 equals(), hashCode(), toString()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class Employee {
 
    private String name;
    private Double salary;
    private LocalDate hireDay;
 
    public Employee(String name, Double salary, int year, int month, int day) {
        this.name = name;
        this.salary = salary;
        hireDay = LocalDate.of(year, month, day);
    }
 
    public String getName() {
        return name;
    }
 
    public Double getSalary() {
        return salary;
    }
 
    public LocalDate getHireDay() {
        return hireDay;
    }
 
    public void raiseSalary(double byPercent) {
        double raise = salary * byPercent / 100;
        salary += raise;
    }
 
    @Override
    public boolean equals(Object otherObject) {
        if (this == otherObject) {
            return true;
        }
 
        if (otherObject == null) {
            return false;
        }
 
        if (getClass() != otherObject.getClass()) {
            return false;
        }
 
        Employee other = (Employee) otherObject;
 
        return Objects.equals(name, other.name) && Objects.equals(salary, other.salary) && Objects.equals(hireDay, other.hireDay);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(name, salary, hireDay);
    }
 
    @Override
    public String toString() {
        return getClass().getName() + "[name = " + name + ", salary = " + salary + ", hireday = " + hireDay + "]";
    }
}

以及他的子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Manager extends Employee{
 
    private double bonus;
 
    public Manager(String name, Double salary, int year, int month, int day) {
        super(name, salary, year, month, day);
        bonus = 0;
    }
 
    @Override
    public Double getSalary() {
        double baseSalary = super.getSalary();
        return baseSalary + bonus;
    }
 
    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
 
    @Override
    public boolean equals(Object otherObject) {
        if (!super.equals(otherObject)) {
            return false;
        }
        Manager other = (Manager) otherObject;
        return bonus == other.bonus;
    }
 
    @Override
    public int hashCode() {
        return super.hashCode() + 17 * new Double(bonus).hashCode();
    }
 
    @Override
    public String toString() {
        return super.toString() + "[bonus = " + bonus + "]";
    }
}