Java的常用类库——java.util.Objects

Objects 与 Object 区别

Object 是 Java 中所有类的基类,位于java.lang包。所有对象(包括数组)都实现此类的方法。

Objects 【public final class Objects extends Object】是 Object 的工具类,位于java.util包。它从jdk1.7开始才出现,被final修饰不能被继承,拥有私有的构造函数。

此类包含static实用程序方法,用于操作对象或在操作前检查某些条件。 这些实用程序包括 null 或 null方法 ,用于计算对象的哈希代码返回对象的字符串比较两个对象,以及检查索引子范围值是否超出范围
在这里插入图片描述

Objects 方法介绍与分析

在这里插入图片描述

1、equals

equals方法 指某个其他对象是否“等于”此对象。(判断两个对象是否相等)

equals方法在非null对象引用上实现等价关系:

  • 自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
  • 对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。
  • 传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true,然后x.equals(z)应该返回true 。
  • 一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false,前提是未修改对象上的equals比较中使用的信息。
  • 对于任何非空的参考值x , x.equals(null)应该返回false 。

在比较两个对象的时候,Object.equals方法容易抛出空指针异常

首先我们来看看在Object类中定义的equals方法 [源码] ↓
在这里插入图片描述
可以看到其源码,在Object类型的equals方法是直接通过== 来比较的,和 ==是没有任何区别的。【故我们通常会重写Object类的equals方法】

请注意,Object类 通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等对象必须具有相等的哈希代码。

a、使用对象的equals方法(Object) 在这里插入图片描述
运行结果:
在这里插入图片描述
所以,对于Object类,则“字符串常量与变量对象比较的时候,常量要写在equals外边,变量放在equals()括号里边。”就是这个原因。如果是两个变量比较的时候,就都需要加非空判断。

b、使用Objects中的equals方法
在这里插入图片描述
这里是引用
注意理解这两个对象,这两个对象都不指向任何地址,也可以理解为都是一个“空指针”【null是没有内存空间的】。

现在,Objects.equals方法中已经做了非空判断,所以不会抛出空指针异常,它是null-save空指针安全的,而且也可以简化代码。

源码如下:
在这里插入图片描述
解释:可以比较两个基本数据类型的数值是否相等,而equals方法依旧调用的是Object对象中的方法,比较两个Object对象的地址值是否引用的同一块地址【因为由Object类的equals方法的源码可以看出实际上就是“==”的比较】,如果不同则为false。

2、deepEquals

顾名思义,深度比较两个对象。
如果两个对象是深层相等,那返回true,否则返回false。

当参数是数组对象,其方法内部采用的是Arrays.deepEquals0方法的算法。

使用Objects.deepEquals方法有个好处,当我们在写业务代码时,可以直接使用此方法来判断两个复杂类型,比如使用了泛型的列表对象List、或者通过反射得到的对象,不清楚对象的具体类型。

源码如下:
在这里插入图片描述
解释:Objects中还有一个deepEquals(Object x,Object y)的方法,此方法的功能比较强大,不仅可以比较数值是否相同,而且还可以比较两个对象中的内容是否相同,如果相同即为true

简短的说明下Arrays.deepEquals0方法:

  • 如果参数是Object类型的数组,则调用Arrays.deepEquals0方法,在参数数组的循环中,递归调用deepEquals0,直到出现不相同的元素,或者循环结束;
  • 如果参数是基本类型的数组,则根据该类型调用Arrays.equals方法。Arrays工具类依照八种基本类型对equals方法做了重载。

调用了Arrays.java中的deepEquals0方法:
在这里插入图片描述
Arrays.java中的deepEquals方法:
在这里插入图片描述
Arrays.java中的euqals方法:以boolean[ ]为例

    public static boolean equals(byte[] a, byte[] a2) {
    
    
        if (a==a2)
            return true;
        if (a==null || a2==null)
            return false;
 
        int length = a.length;
        if (a2.length != length)
            return false;
 
        for (int i=0; i<length; i++)
            if (a[i] != a2[i])
                return false;
 
        return true;
    }

上面涉及的代码比较多,大意就是:

a、如果deepEquals(Object a, Object b)中的a和b是两个数组对象,对每一个索引,用==(如果元素是对象,也会使用equals)作用于两个数组的对应元素,全通过返回true;

b、如果deepEquals(Object a, Object b)中的a和b是两个非数组,==为true或者对象的equals为true则返回true。

Objects中的equals和deepEquals二者方法的区别

链接:二者方法的区别

3、isNull

判空方法,如果参数为空则返回true。从jdk1.8开始。

源码如下:
在这里插入图片描述
API Note: 该方法的存在是用于java.util.function.Predicate类;filter(Objects::isNull)。
来看下Predicate类中,使用到本方法的代码:

 static <T> Predicate<T> isEqual(Object targetRef) {
    
    
        return (null == targetRef)  
                ? Objects::isNull   // 双冒号,代表方法引用。
                : object -> targetRef.equals(object); // 此处为lambda表达式。接收object对象,返回参数targetRef与该对象的比较结果。
    }

4、nonNull

判断非空方法,如果参数不为空则返回true。从jdk1.8开始。

源码如下:
在这里插入图片描述
APINote: 该方法的存在是用于java.util.function.Predicate类,filter(Objects::nonNull)。

5、requireNonNull

requireNonNull(T obj)

检查指定类型的对象引用是否为空null。当参数为null时,抛出空指针异常,否则正常输出obj。
设计这个方法主要是为了在方法、构造方法中做参数校验。【常用于要求对象不能为空的场景】

源码如下:
在这里插入图片描述

举例1:
在这里插入图片描述
举例2:
当我们通过带参的构造方法创建对象时,创建对象的同时就可以进行参数校验。同时也简化了很多代码。
在这里插入图片描述

requireNonNull(T obj, String message)

该方法是requireNonNull的重载方法,当被校验的参数为null时,根据第二个参数message抛出自定义的异常消息。

源码如下:
在这里插入图片描述

举例:
在这里插入图片描述

6、requireNonNull系列

requireNonNull(T obj, Supplier messageSupplier)

检查指定的对象引用是否为空null,如果是空,抛出自定义的空指针异常。从jdk1.8开始。

与方法requireNonNull(Object, String)不同,此方法允许创建要延迟的消息,直到进行空检查。 虽然这可以在非空情况下赋予性能优势,但在决定调用此方法时,应注意创建消息提供者的成本小于仅直接创建字符串消息的成本。

源码如下:
在这里插入图片描述

requireNonNullElse

如果第一个参数是非 null ,则返回第一个参数obj,反之调用requireNonNull(T obj, String message)方法来判断【第二个参数非null,则直接返回第二个参数】。

源码如下:
在这里插入图片描述

举例
在这里插入图片描述

requireNonNullElseGet

如果它是非 null ,则返回第一个参数,否则返回非 null值 supplier.get() 。

源码如下:
在这里插入图片描述

小结

requireNonNull就相当于是一个检查是否为null的过滤器,如果为null则抛出异常,反之返回原对象。
requireNonNullElse把上一个方法升级了,如果当前对象是null,则让defaultObj替补上去,看看此对象是否为空。
第三个则是反复嵌套两次。

7、hashCode

返回一个整型数值,表示该对象的哈希码值。若参数对象为空,则返回整数0;若不为空,则直接调用了Object.hashCode方法。

源码如下:
在这里插入图片描述

举例:
在这里插入图片描述

Object支持hashCode方法是为了提高哈希表(例如java.util.Hashtable 提供的哈希表)的性能。

以集合Set为例,当新加一个对象时,需要判断现有集合中是否已经存在与此对象相等的对象,如果没有hashCode()方法,需要将Set进行一次遍历,并逐一用equals()方法判断两个对象是否相等,此种算法时间复杂度为o(n)。通过借助于hasCode方法,先计算出即将新加入对象的哈希码,然后根据哈希算法计算出此对象的位置,直接判断此位置上是否已有对象即可。
(注:Set的底层用的是Map的原理实现)

8、hash

为一系列的输入值生成哈希码,该方法的参数是可变参数。

源码如下:
在这里插入图片描述
它是将所有的输入值都放到一个数组,然后调用Arrays.hashCode(Object[])方法来实现哈希码的生成。

对于当一个对象包含多个成员,重写Object.hashCode方法时,hash方法非常有用。

该方法对于有多个字段的对象实现哈希值很有用,例如: 一个对象有三个字段x,y,z, 则可以通过如下方式获取对象的哈希值:
在这里插入图片描述

警告: 当提供的参数是一个对象的引用,返回值不等于该对象引用的哈希码。这个值可以通过调用hashCode方法来计算。

9、toString

toString(Object o)

返回指定对象的字符串形式。如果参数为空 对象null,则返回字符串“null”。

源码如下:
在这里插入图片描述
String类的valueOf方法:String.valueOf(Object obj)方法的内部实现为
在这里插入图片描述
java.lang.Object类的toString()方法:Object.toString()方法的内部实现为
在这里插入图片描述
返回字符串值,即:类的全限定名 + @ + 16进制码

toString(Object o, String nullDefault)

返回指定对象的字符串表示形式。如果参数为空对象null,则返回第二个参数nullDefault所指定的对象。

源码如下:
在这里插入图片描述

10、compare

如果两个参数相同则返回整数0。因此,如果两个参数都为空对象null,也是返回整数0。

注意:如果其中一个参数是空对象null,是否会抛出空指针异常NullPointerException取决于排序策略,如果有的话,则由Comparator来决定空值null。

源码如下:
在这里插入图片描述

11、Index系列

checkIndex

检查index是否在0 (含)到length (不包括)范围内。

如果以下任何不等式为真,则定义index超出范围:

  • index < 0
  • index >= length
  • length < 0 ,这是前者的不平等所暗示的

源码如下:
在这里插入图片描述

checkFromToIndex

检查是否在子范围从fromIndex (包括)到toIndex (不包括)是范围界限内0 (包括)到length (不包括)。

如果以下任何不等式为真,则子范围被定义为超出界限:

  • fromIndex < 0
  • fromIndex > toIndex
  • toIndex > length
  • length < 0,这是前者的不平等所暗示的

源码如下:
在这里插入图片描述
简单理解就是1-2是不是在区间0-3内;

checkFromIndexSize

检查是否在子范围从fromIndex (包括)到fromIndex + size (不包括)是范围界限内0 (包括)到length (不包括)。

如果以下任何不等式为真,则子范围被定义为超出界限:

  • fromIndex < 0
  • size < 0
  • fromIndex + size > length ,考虑到整数溢出
  • length < 0 ,这是前者的不平等所暗示的

源码如下:
在这里插入图片描述
简单理解就是是否越界,意思就是1+(1+size)是不是在区间0-3内;

ps:
近期要把JDK的一些常用类库的源码整理出来,欢迎大家指正和讨论。

如果有错误的地方,欢迎各位指正。

如果您觉得还不错,点个赞的话 我会很感激的,谢谢~

猜你喜欢

转载自blog.csdn.net/weixin_46312449/article/details/113181868