2

Java 8中 Objects 类源码实现与分析

 2 years ago
source link: https://blog.51cto.com/u_15724795/5557925
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java 8中 Objects 类源码实现与分析

推荐 原创

然笑后端 2022-08-09 09:19:55 博主文章分类:水煮JDK源码 ©著作权

文章标签 java Objects 源码分析 文章分类 Java 编程语言 yyds干货盘点 阅读数298

这是 《水煮 JDK 源码》系列 的第 10 篇文章,计划撰写100篇关于JDK源码相关的文章

Objects 类位于 java.util 包下,自 JDK 1.7 版本新增的,它是一个 final 类,不能被继承,且构造函数是 private 的,不能被实例化,它提供了一系列操作Object对象的静态方法,通常会被当做工具类去使用,其类定义如下:

public final class Objects {}

Objects 类在 jdk 源码中应用很广泛,通过 Intellij Idea 搜索一下在 rt.jar 包中的应用,部分截图如下:

Java 8中 Objects 类源码实现与分析_java

从上面的搜索结果可以看出,在 jdk 1.8 版本中,大概有 366 处使用了 Objects 类的相关方法,下面结合具体的源码来分析一下。

1、构造函数

Objects 类不能被实例化,其构造函数是私有的,实现如下:

private Objects() {
    throw new AssertionError("No java.util.Objects instances for you!");
}

Objects 类提供的静态方法大致可以分为以下的几类:

  • equals:比较两个对象是否相同
  • hash:获取对象的哈希值;
  • toString:将对象转换为字符串
  • requireNonNull:要求对象不为空
  • isNull:判断对象是否为空
  • nonNull:判断对象不为空

具体可以通过下面的结构图来看看这些方法:

Java 8中 Objects 类源码实现与分析_Objects_02

2.1 equals 方法

equals() 方法主要用于比较两个指定的对象是否相同,定义如下:

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

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

在比较数组对象是否相同时,具体调用的是 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
        // 如果不是数组类型,则直接使用 Object.equals() 方法比较
        eq = e1.equals(e2);
    return eq;
}

上面的方法实现中,会逐个比较数组中的元素是否相同,如果都相同,则两个数组相同。

2.2 hashCode 方法

hashCode() 方法用于获取对象的哈希值,其实现如下:

public static int hashCode(Object o) {
    // 如果对象不为空,则调用 Object 的 hashCode() 方法
    // 否则直接返回 0
    return o != null ? o.hashCode() : 0;
}

除了可以获取单个对象的哈希值外,Objects 还提供了可以获取多个对象的哈希值,即 hash() 方法,如下:

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

该方法的参数为可变长参数,具体实现是调用 Arrays.hashCode 方法,其源码如下:

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

从上面的实现可以看出,数组元素的哈希值是所有元素的哈希值经过一定变换后的和。

2.3 toString 方法

toString() 方法就是将对象转换为字符串,如果对象为 null,则会直接返回 null 字符串,其实现如下:

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

public static String toString(Object o, String nullDefault) {
    // 如果对象为null,则可以返回一个默认值
    return (o != null) ? o.toString() : nullDefault;
}

toString() 方法具体实现调用的是 String.valueOf() 方法,而 String.valueOf() 方法又会调用 Object.toString() 方法,其源码如下:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

2.4 requireNonNull 方法

requireNonNull() 方法用于判定参数对象是否为空,如果对象为空,则会抛出空指针异常,其实现如下:

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) {
    // 通过一个 Supplier 来获取空指针异常信息
    if (obj == null)
        throw new NullPointerException(messageSupplier.get());
    return obj;
}

requireNonNull() 有3个重载方法,可以指定抛出空指针异常时的信息,对于第三个方法,可以传入一个 Supplier,在对象为空时,动态的构建空指针异常信息,如果一个方法要求参数不能为空,那么就可以直接使用该方法对参数进行空校验。

2.5 isNull 方法

isNull() 方法判定对象为空,其实现比较简单,如下:

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

在平时的编程过程中,如果需要判断对象等于 null 时,也可以使用 Objects.isNull() 方法替代。

2.6 nonNull 方法

isNull() 方法相反,nonNull() 方法用于判断对象不为空,其实现也比较简单,如下:

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

整个 Objects 类的源码还是比较少的,主要作为一个工具类去使用,对于平时的空判断、非空判断或者参数校验,都可以尝试使用 Objects 类替代,可以使代码更加简洁。

  • 收藏
  • 评论
  • 分享
  • 举报

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK