好用的`java.util.Objects`类

在jdk1.7中,新增了一个工具类,就是java.util.Objects类。它有3个简单的封装方法,对于平常的使用来说挺有用的,分别是:hashCodeequalstoString这3个方法。

1、hashcode生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 1. Objects.hash(Object... values)
public static int hash(Object... values) {
return Arrays.hashCode(values);
}

// 2. Arrays.hashCode(Object a[])
public static int hashCode(Object a[]) {
if (a == null)
return 0;

int result = 1;

for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());

return result;
}

// 3. Object.hashCode()
public native int hashCode();

首先,Objects的hash方法接收可变参数,可变参数的内部是一个数组。然后内部调用Arrays的hashCode方法,我们来看一下其方法:核心是遍历每一个参数来计算result值,在计算的过程中,每一个参数上转型为Object使用hashCode来生成随机值。那么Object的hashCode又是什么?这是一个本地方法,源码不给出实现,其数值和对象的内存地址有关。

参数虽然上转型为Object,但是对于String、Integer等对象类型,它们都重写了hashCode方法。

因为是基于内存地址的生成,所以不同对象生成的hashcode值冲突的几率是很小的。

2、对象equals比较

1
2
3
4
5
6
7
8
9
// 1. Objects.equals(Object a, Object b)
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}

// 2. Object.equals(Object obj)
public boolean equals(Object obj) {
return (this == obj);
}

首先是对象的引用判断,其次就是调用对象自身的equals方法来比较,如果对象类型没有重写equals的话,就会调用Object的equals方法(仍然是对象的引用比较)。

事实上,我们进行equals比较的对象,除了引用对象之外,就是String、Integer(自动装箱后)等类型了。

对于String,直接进行引用比较。而对于Integer、Double等对象类型,它们都重写了equals方法,贴出Integer的equals方法:

1
2
3
4
5
6
7
> public boolean equals(Object obj) {
> if (obj instanceof Integer) {
> return value == ((Integer)obj).intValue();
> }
> return false;
> }
>

可以看到,内部是进行值相等判断。

hashCode与equals方法的重要性

对于散列结构(hash)的集合类型,比如说HashMap、HashSet等,如果我们用它们来存储我们自定义的对象,那么我们就必要重写类的hashCode与equals方法。为什么要重写,这个原因就不赘述了。 还有Set集合类,由于它存储不重复的元素。

下面我们给出利用Objects工具类的一种较为简单实用的重写方式:

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
public class Building {

private String name;
private double area;

@Override
public int hashCode() {
return Objects.hash(name, area);
}

@Override
public boolean equals(Object obj) {
// 引用相等判断
if (obj == this) {
return true;
}
// 类型判断
if (!(obj instanceof Building)) {
return false;
}
Building building = (Building) obj;
// 关键域相等判断
// 基本类型不要用用Objects.equals()方法,会自动装箱带来额外开销
return Objects.equals(name, building.name) && (area == building.area);
}

@Override
public String toString() {
return Objects.toString("name = " + name, "name is undefined") + ", "
+ Objects.toString("area = " + area, "area is undefined");
}

// setter、getter
}

3、toString

我们自己重写toString方法时,有一点比较难写,就是默认值设置。

1
2
3
4
5
6
7
8
9
// Objects.toString(Object o, String nullDefault)
public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}

// Objects.toStirng(Object 0)
public static String toString(Object o) {
return String.valueOf(o);
}

我们在重写toString时,可以参考上面的Building类的写法。

最近的文章

日期(Date)与时间(Time)

在mysql中,与日期、时间相关的数据类型有:DATE、TIME、DATETIME、TIMESTAMP 这4种。 基本介绍DATE DATE就是日期,日期就是形如YYYY-MM-DD 格式的字符串,它的范围是:1000-01-01-9999-12-31 。官网上讲,允许使用strings和numb …

date与time, mysql 继续阅读
更早的文章

Java中的数值类型选择

整数类型有byte(1 byte),short(2 byte),int(4 byte),long(8 byte)等基本数据类型,取值的范围不一样。 1234byte x1 = 1;short x2 = 2;int x3 = 3;long x4 = 4L; 涉及到有小数的数值这种场景也是要分情况讨论的 …

数值类型 继续阅读