JDK 自带Objects类 方法解析

Objects 对于Object 的关系类似于Collections 对于Collect,十分有意思

----------------------------------------------------------------------------------------------

更新:辛苦码了这么多字,结果发现一篇更好的博客,出于良心,文章就成转载的了


1.Objects 的equals方法

比较两个对象是否相等,依赖于对象重写的equals方法(或object 的equals 方法比较地址)

  public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

2.deepEqualsf方法底层调用Arrays类的比较方法,因此一般可以比较 基本数组,如果是对象的话则依赖于对象自身的equals方法

//Objects 类
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);
    }


//Arrays 类

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;
    }


3.toString 方法 调用String类的valueof 方法,当对象为null时,输出“null”,一定程度上防止直接toString的空指针

    public static String toString(Object o) {
        return String.valueOf(o);
    }

//当o为null时,使用非空默认值
public static String toString(Object o, String nullDefault) {
        return (o != null) ? o.toString() : nullDefault;
    }

4.非空判断,要求一个对象非空,如果为空则抛出异常。spring 项目可以使用Asserts.notNull(Obj,message)来断言,java也有,

甚至你好可以在pom文件中引入

<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>jsr305</artifactId>
    <version>3.0.2</version>
</dependency>
<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency>
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>20.0</version>
</dependency>

直接在虚参声明中写@NotNull @NonNul 之类的,让调用者去做空指针判断

    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }



    public static <T> T requireNonNull(T obj, String message) {
        if (obj == null)
            throw new NullPointerException(message);
        return obj;
    }


    public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
        if (obj == null)
            throw new NullPointerException(messageSupplier.get());
        return obj;
    }

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

发现了一片更好的博客,转载过来 

https://www.cnblogs.com/quiet-snowy-day/p/6387321.html#label_0

 

Objects 与 Object 区别

Object 是 Java 中所有类的基类,位于java.lang包。

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

它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),用于计算对象的hashcode、返回对象的字符串表示形式、比较两个对象。

 

Objects 各方法介绍与分析

equals

equals方法是判断两个对象是否相等。

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

——我刚上班的时候,有位老员工教我“字符串常量与变量对象比较的时候,常量要写在equals外边,变量放在equals()括号里边。” 就是这个原因。

如果是两个变量比较的时候,就都需要加非空判断。

* Object.equals方法内调用的是return (this == obj)。String类中是依据字符串内容是否相等来重定义了equals方法。

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

源码如下:

    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

返回目录

 

 

deepEquals

顾名思义,深度比较两个对象。

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

使用Objects.deepEquals方法有个好处,当我们在写业务代码时,可以直接使用此方法来判断两个复杂类型,

比如使用了泛型的列表对象List<T>、或者通过反射得到的对象,不清楚对象的具体类型。

源码如下:

复制代码

    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);
    }

复制代码

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

     如果参数是Object类型的数组,则调用Arrays.deepEquals方法,在参数数组的循环中,递归调用deepEquals0,直到出现不相同的元素,或者循环结束;

     如果参数是基本类型的数组,则根据该类型调用Arrays.equals方法。Arrays工具类依照八种基本类型对equals方法做了重载。

 

返回目录

 

 

hashCode

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

源码如下:

    public static int hashCode(Object o) {
        return o != null ? o.hashCode() : 0;
    }

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

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

(注:Set的底层用的是Map的原理实现)

 

返回目录

 

 

hash

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

源码如下:

    public static int hash(Object... values) {
        return Arrays.hashCode(values);
    }

它是将所有的输入值都放到一个数组,然后调用Arrays.hashCode(Object[])方法来实现哈希码的生成。

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

举个Java源码中的例子:

java.lang.invoke.MemberName 类,该类有Class<?> clazz、String name、Object type、int flags、Object resoulution这几个成员变量,

该类的hashCode方法如下:

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

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

 

返回目录

 

 

toString

  toString(Object o)

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

  该方法内部调用的是

    return String.valueOf(o);

  String.valueOf(Object obj)方法的内部实现为

    return (obj == null) ? "null" : obj.toString();

  Object.toString()方法的内部实现为

    return getClass().getName() + "@" + Integer.toHexString(hashCode());

  toString(Object o, String nullDefault)

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

返回目录

 

 

compare

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

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

源码如下:

    public static <T> int compare(T a, T b, Comparator<? super T> c) {
        return (a == b) ? 0 :  c.compare(a, b);
    }

返回目录

 

 

requireNonNull

  requireNonNull(T obj)

  检查指定类型的对象引用不为空null。当参数为null时,抛出空指针异常。设计这个方法主要是为了在方法、构造函数中做参数校验。

  源码如下:

    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

  举个例子:

  当我们通过带参的构造函数创建对象时,创建对象的同时就可以进行参数校验。同时也简化了很多代码。

     public class Foo {
          public Foo(Bar bar) {
               this.bar = Objects.requireNonNull(bar);
          }
     }

 

  requireNonNull(T obj, String message) 

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

  源码如下:

    public static <T> T requireNonNull(T obj, String message) {
        if (obj == null)
            throw new NullPointerException(message);
        return obj;
    }

 

  requireNonNull(T obj, Supplier<String> messageSupplier)

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

  与requireNonNull(Object, String)方法不同,本方法允许将消息的创建延迟,直到空检查结束之后。

  虽然在非空例子中这可能会带来性能优势, 但是决定调用本方法时应该小心,创建message supplier的开销低于直接创建字符串消息。  

  源码如下:

    public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
        if (obj == null)
            throw new NullPointerException(messageSupplier.get());
        return obj;
    }

 

isNull

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

源码如下:

    public static boolean isNull(Object obj) {
        return obj == null;
    }

apiNote: 该方法的存在是用于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与该对象的比较结果。
    }

 

 

nonNull

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

源码如下:

    public static boolean nonNull(Object obj) {
        return obj != null;
    }

apiNote: 该方法的存在是用于java.util.function.Predicate类,filter(Objects::nonNull)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章