2017-02-10 by 安静的下雪天  http://www.cnblogs.com/quiet-snowy-day/p/6387321.html   

本篇概要

    equals    deepEquals   hashCode   hash

    toString   compare   requireNonNull   isNull   nonNull

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空指针安全的,而且也可以简化代码。

源码如下:

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

返回目录

 

deepEquals

顾名思义,深度比较两个对象。
当参数是数组对象,其方法内部采用的是Arrays.deepEquals0方法的算法。
使用Objects.deepEquals方法有个好处,当我们在写业务代码时,可以直接使用此方法来判断两个复杂类型,
比如使用了泛型的列表对象List<T>、或者通过反射得到的对象,不清楚对象的具体类型。
源码如下:
  1. public static boolean deepEquals(Object a, Object b) {
  2. if (a == b)
  3. return true;
  4. else if (a == null || b == null)
  5. return false;
  6. else
  7. return Arrays.deepEquals0(a, b);
  8. }

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

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

返回目录

 

hashCode

返回一个整型数值,表示该对象的哈希码值。若参数对象为空,则返回整数0;若不为空,则直接调用了Object.hashCode方法。
源码如下:
  1. public static int hashCode(Object o) {
  2. return o != null ? o.hashCode() : 0;
  3. }

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

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

返回目录

 

hash

为一系列的输入值生成哈希码,该方法的参数是可变参数。
源码如下:
  1. public static int hash(Object... values) {
  2. return Arrays.hashCode(values);
  3. }

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

对于当一个对象包含多个成员,重写Object.hashCode方法时,hash方法非常有用。
举个Java源码中的例子:
java.lang.invoke.MemberName 类,该类有Class<?> clazz、String name、Object type、int flags、Object resoulution这几个成员变量,
该类的hashCode方法如下:
  1. @Override
  2. public int hashCode() {
  3. return Objects.hash(clazz, getReferenceKind(), name, getType());
  4. }

警告:当提供的参数是一个对象的引用,返回值不等于该对象引用的散列码。这个值可以通过调用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。
源码如下:
  1. public static <T> int compare(T a, T b, Comparator<? super T> c) {
  2. return (a == b) ? 0 : c.compare(a, b);
  3. }

返回目录

 

requireNonNull

  requireNonNull(T obj)

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

  源码如下:

  1. public static <T> T requireNonNull(T obj) {
  2. if (obj == null)
  3. throw new NullPointerException();
  4. return obj;
  5. }

  举个例子:

  当我们通过带参的构造函数创建对象时,创建对象的同时就可以进行参数校验。同时也简化了很多代码。
  1. public class Foo {
  2. public Foo(Bar bar) {
  3. this.bar = Objects.requireNonNull(bar);
  4. }
  5. }

  requireNonNull(T obj, String message) 

  该方法是requireNonNull的重载方法,当被校验的参数为null时,根据第二个参数message抛出自定义的异常消息。
  源码如下:
  1. public static <T> T requireNonNull(T obj, String message) {
  2. if (obj == null)
  3. throw new NullPointerException(message);
  4. return obj;
  5. }

  requireNonNull(T obj, Supplier<String> messageSupplier)

  检查指定的对象引用不为空null,如果是空,抛出自定义的空指针异常。从jdk1.8开始。
  与requireNonNull(Object, String)方法不同,本方法允许将消息的创建延迟,直到空检查结束之后。
  虽然在非空例子中这可能会带来性能优势, 但是决定调用本方法时应该小心,创建message supplier的开销低于直接创建字符串消息。  
  源码如下:
  1. public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
  2. if (obj == null)
  3. throw new NullPointerException(messageSupplier.get());
  4. return obj;
  5. }

返回目录

 

isNull

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

源码如下:

  1. public static boolean isNull(Object obj) {
  2. return obj == null;
  3. }
apiNote: 该方法的存在是用于java.util.function.Predicate类,filter(Objects::isNull)。
来看下Predicate类中,使用到本方法的代码: 
  1. static <T> Predicate<T> isEqual(Object targetRef) {
  2. return (null == targetRef)
  3. ? Objects::isNull // 双冒号,代表方法引用。
  4. : object -> targetRef.equals(object); // 此处为lambda表达式。接收object对象,返回参数targetRef与该对象的比较结果。
  5. }
 

nonNull

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

源码如下:

  1. public static boolean nonNull(Object obj) {
  2. return obj != null;
  3. }

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

返回目录

参考资料:

如果觉得有帮助,请鼓励下博主吧:)

【Java】java.util.Objects 源码学习的更多相关文章

  1. 【Java】Objects 源码学习

    2017-02-10 by 安静的下雪天  http://www.cnblogs.com/quiet-snowy-day/p/6387321.html    本篇概要 Objects 与 Object ...

  2. Java数据结构: java.util.BitSet源码学习

    接着上一篇Blog:一道面试题与Java位操作 和 BitSet 库的使用,分析下Java源码中BitSet类的源码. 位图(Bitmap),即位(Bit)的集合,是一种常用的数据结构,可用于记录大量 ...

  3. Java中Integer的源码学习

      一.开始 public final class Integer extends Number implements Comparable<Integer> 1).由于类修饰符中有关键字 ...

  4. 【jdk源码2】Objects源码学习

    在学习上一个类TreeMap的时候,提到了这个类,这个类是jdk1.7新增的,里面有很多实用的方法.就是一个工具类,熟悉以后,如果里面有已经实现的方法,那么就不要再去实现了,省时省力省测试. 一.简单 ...

  5. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  6. Java并发包源码学习之AQS框架(一)概述

    AQS其实就是java.util.concurrent.locks.AbstractQueuedSynchronizer这个类. 阅读Java的并发包源码你会发现这个类是整个java.util.con ...

  7. Java并发包源码学习系列:ReentrantLock可重入独占锁详解

    目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...

  8. Java并发包源码学习系列:ReentrantReadWriteLock读写锁解析

    目录 ReadWriteLock读写锁概述 读写锁案例 ReentrantReadWriteLock架构总览 Sync重要字段及内部类表示 写锁的获取 void lock() boolean writ ...

  9. Java并发包源码学习系列:详解Condition条件队列、signal和await

    目录 Condition接口 AQS条件变量的支持之ConditionObject内部类 回顾AQS中的Node void await() 添加到条件队列 Node addConditionWaite ...

随机推荐

  1. 分布式技术 memcached

    memcached 是一个高性能的分布式内存对象缓存系统,用于动态web应用,以减轻数据库负载,它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.memcache ...

  2. elasticsearch中如何手动控制全文检索结果的精准度

    1.为帖子数据增加标题字段 POST /forum/article/_bulk{ "update": { "_id": "1"} }{ &q ...

  3. 0.00-050613_boot.s

    ! boot.s ! ! It then loads the system at 0x10000, using BIOS interrupts. Thereafter ! it disables al ...

  4. Oracle大数据表的分表处理

    1.首先给大数据表创建rownum序列号 --增加序列号字段 alter table TEST add xlh number; --填充序列号 update TEST set xlh = rownum ...

  5. 写hibernate.cfg.xml时报错The content of element type "property" must match "(meta*,(column|formula)*,type?)".

    原配置文件是这样的 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-ma ...

  6. R语言:导入导出数据

    主要学习如何把几种常用的数据格式导入到R中进行处理,并简单介绍如何把R中的数据保存为R数据格式和csv文件. 1.保存和加载R的数据(与R.data的交互:save()函数和load()函数) a & ...

  7. 通过例子深入理解javascript中的new操作符

    1.首先看一道题目 function Cat(name,age){ this.name=name; this.age=age; } console.log(new Cat('miaomiao',18) ...

  8. BitmapUtil(高效压缩不失真)

    package com.changim.patient.app.utils; import android.app.Activity; import android.content.ContentRe ...

  9. 2018.7.24 Error Code

    来不及解释了,写下再说 -------------------------------------------- SUCCESS = 0, RTC_SELFTEST_FAILED = 1,      ...

  10. const指针和指向const的指针

    int *const p=&a; 这是const指针,这种指针必须在定义时就给出它所指向的地址,否则会error:uninitialized const 'p'.const指针的指针本身是co ...