java.util.Objects工具类详解
简介
Objects 与 Object 区别
- Object 是 Java 中所有类的基类,位于java.lang包。
- Objects 是 Object 的工具类,位于java.util包。
java.util.Objects由 Java 7 引入的 ,包含static实用程序方法,用于操作对象或在操作前检查某些条件。
需要注意的是:这个类用关键字final修饰不能被继承,拥有私有的构造函数。
问题描述:
用户希望使用静态工具方法实现非空验证、比较等操作。
适用场景:
它在流处理中相当有用,实用程序包括null或null方法,用于计算对象的哈希代码,返回对象的字符串,比较两个对象,以及检查索引或子范围值是否超出范围。
构造函数
private Objects() {
throw new AssertionError("No java.util.Objects instances for you!");
}
可以看到Objects类中只有一个构造函数,并且声明为private,构造函数中抛出一个AssertionError。因此这个类不可以实例化。
常用方法
equals
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
这里Objects.equals方法中已经做了非空判断,所以不会抛出空指针异常,它是null-save空指针安全的。
如果两个参数相等,返回true,否则返回false。 因此,如果这两个参数是null ,返回true,如果只有一个参数为null ,返回false, 否则,通过使用第一个参数的equals方法确定相等性。
deepEquals
public static boolean deepEquals(Object a, Object b) {
if (a == b)
return true;
else if (a == null || b == null)
return false;
else
return Arrays.deepEquals0(a, b);
}
若两个都是null值的字符串或者数组比较,返回true。如果两个参数都是数组,则使用Arrays.deepEquals中的算法来确定相等性,在参数数组的循环中,递归调用deepEquals0,直到出现不相同的元素, 或者循环结束;否则,通过使用第一个参数的equals方法确定相等性。
注:该方法在数组比较中尤其有用,当我们在业务中需要判断两个复杂类型,比如使用了泛型的列表对象List、或者通过反射得到的对象,不清楚对象的具体类型时可以直接使用此方法来解决。
测试:
public static void main(String[] args) {
String[] arr1 = new String[]{"123"};
String[] arr2 = new String[]{"124"};
int[] arr3 = new int[]{1,2,3};
int[] arr4 = new int[]{1,2,3};
String s1 = "100";
int s2 = 100;
boolean b1 = Objects.deepEquals(arr1,arr2);
boolean b2 = Objects.deepEquals(arr3,arr4);
boolean b3 = Objects.deepEquals(s1,s2);
System.out.println("字符串数组比较结果:"+b1);
System.out.println("整型数组比较结果:"+b2);
System.out.println("字符串和整型比较结果:"+b3);
}
结果为:
Arrays.deepEquals0方法的源代码如下:
static boolean deepEquals0(Object e1, Object e2) {
assert e1 != null;
boolean eq;
if (e1 instanceof Object[] && e2 instanceof Object[])
eq = deepEquals ((Object[]) e1, (Object[]) e2);
else if (e1 instanceof byte[] && e2 instanceof byte[])
eq = equals((byte[]) e1, (byte[]) e2);
else if (e1 instanceof short[] && e2 instanceof short[])
eq = equals((short[]) e1, (short[]) e2);
else if (e1 instanceof int[] && e2 instanceof int[])
eq = equals((int[]) e1, (int[]) e2);
else if (e1 instanceof long[] && e2 instanceof long[])
eq = equals((long[]) e1, (long[]) e2);
else if (e1 instanceof char[] && e2 instanceof char[])
eq = equals((char[]) e1, (char[]) e2);
else if (e1 instanceof float[] && e2 instanceof float[])
eq = equals((float[]) e1, (float[]) e2);
else if (e1 instanceof double[] && e2 instanceof double[])
eq = equals((double[]) e1, (double[]) e2);
else if (e1 instanceof boolean[] && e2 instanceof boolean[])
eq = equals((boolean[]) e1, (boolean[]) e2);
else
eq = e1.equals(e2);
return eq;
}
若参数是基本类型的数组,则根据该类型调用Arrays.equals方法。Arrays工具类依照八种基本类型对equals方法做了重载。
hashCode
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
判断引用o所指对象是否为null,不为null,则返回o所指对象的hasCode方法执行结果,为null,返回0。
hash
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
为一系列的输入值生成哈希码,该方法的参数是可变参数。它将所有的输入值都放到一个数组,然后调用Arrays.hashCode(Object[])方法来实现哈希码的生成。
警告:当提供的参数是单个对象的引用时,返回值不等于该对象引用的散列码。这个值可以通过调用hashCode(Object)方法来计算。
public static int 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;
}
toString
toString(Object o)
public static String toString(Object o) {
return String.valueOf(o);
}
返回指定对象的字符串表示形式。如果参数为null,则返回字符串“null”。
String.valueOf(Object obj)方法的内部实现:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Object.toString()方法的内部实现:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString(Object o, String nullDefault)
public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}
若第一个参数不是 null ,则返回在第一个参数上调用 toString的结果,否则返回第二个参数。
compare
public static <T> int compare(T a, T b, Comparator<? super T> c) {
return (a == b) ? 0 : c.compare(a, b);
}
注意:若其中一个参数为null ,是否会抛出空指针异常NullPointerException取决于排序策略,如果有的话,则由Comparator来决定空值null。
代码实例:
int num1 = 100;
int num2 = 200;
System.out.println(Objects.compare(num2, num1, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
if (o1 - o2 > 0){
return 1;
}else{
return -1;
}
}
}));
System.out.println(Objects.compare(new Object(), new Object(), new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return o1.hashCode() - o2.hashCode();
}
}));
requireNonNull
requireNonNull(T obj)
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
检查指定的对象引用是不是null 。若为null,则抛出空指针异常,否则返回对象本身。此方法主要用于在方法和构造函数中进行参数校验,如下所示:
public Foo(Bar bar) {
this.bar = Objects.requireNonNull(bar);
}
当我们通过带参的构造函数创建对象时,创建对象的同时就可以进行参数校验。
requireNonNull(T obj, String message)
public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}
该方法是requireNonNull的重载方法,当被校验的参数为null时,根据第二个参数message抛出自定义的NullPointerException 。
注:此方法主要用于在具有多个参数的方法和构造函数中进行参数校验,如下所示:
public Foo(Bar bar, Baz baz) {
this.bar = Objects.requireNonNull(bar, "bar must not be null");
this.baz = Objects.requireNonNull(baz, "baz must not be null");
}
isNull
public static boolean isNull(Object obj) {
return obj == null;
}
判空方法,如果参数为null则返回true,否则返回false。
nonNull
public static boolean nonNull(Object obj) {
return obj != null;
}
判断非空方法,若参数是非空,返回true,否则返回false。