好用的java.util.Objects
类
在jdk1.7中,新增了一个工具类,就是java.util.Objects
类。它有3个简单的封装方法,对于平常的使用来说挺有用的,分别是:hashCode
、equals
、toString
这3个方法。
1、hashcode生成
// 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. 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方法:
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
可以看到,内部是进行值相等判断。
hashCode与equals方法的重要性
对于散列结构(hash)的集合类型,比如说HashMap、HashSet等,如果我们用它们来存储我们自定义的对象,那么我们就必要重写类的hashCode与equals方法。<u>为什么要重写,这个原因就不赘述了。</u> 还有Set集合类,由于它存储不重复的元素。
下面我们给出利用Objects工具类的一种较为简单实用的重写方式:
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方法时,有一点比较难写,就是默认值设置。
// 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
类的写法。