好用的java.util.Objects類

weixin_33806914發表於2018-08-12

好用的java.util.Objects

在jdk1.7中,新增了一個工具類,就是java.util.Objects類。它有3個簡單的封裝方法,對於平常的使用來說挺有用的,分別是:hashCodeequalstoString這3個方法。

1、hashcode生成

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

// 2. Arrays.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;
}

// 3. Object.hashCode()
public native int hashCode();

首先,Objects的hash方法接收可變引數,可變引數的內部是一個陣列。然後內部呼叫Arrays的hashCode方法,我們來看一下其方法:核心是遍歷每一個引數來計算result值,在計算的過程中,每一個引數上轉型為Object使用hashCode來生成隨機值。那麼Object的hashCode又是什麼?這是一個本地方法,原始碼不給出實現,其數值和物件的記憶體地址有關。

引數雖然上轉型為Object,但是對於String、Integer等物件型別,它們都重寫了hashCode方法。

因為是基於記憶體地址的生成,所以不同物件生成的hashcode值衝突的機率是很小的。

2、物件equals比較

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

// 2. Object.equals(Object obj)
public boolean equals(Object obj) {
  return (this == obj);
}

首先是物件的引用判斷,其次就是呼叫物件自身的equals方法來比較,如果物件型別沒有重寫equals的話,就會呼叫Object的equals方法(仍然是物件的引用比較)。

事實上,我們進行equals比較的物件,除了引用物件之外,就是String、Integer(自動裝箱後)等型別了。

對於String,直接進行引用比較。而對於Integer、Double等物件型別,它們都重寫了equals方法,貼出Integer的equals方法:

public boolean equals(Object obj) {
  if (obj instanceof Integer) {
      return value == ((Integer)obj).intValue();
  }
    return false;
}

可以看到,內部是進行值相等判斷。

hashCode與equals方法的重要性

對於雜湊結構(hash)的集合型別,比如說HashMap、HashSet等,如果我們用它們來儲存我們自定義的物件,那麼我們就必要重寫類的hashCode與equals方法。<u>為什麼要重寫,這個原因就不贅述了。</u> 還有Set集合類,由於它儲存不重複的元素。

下面我們給出利用Objects工具類的一種較為簡單實用的重寫方式:

public class Building {

    private String name;
    private double area;

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

    @Override
    public boolean equals(Object obj) {
          // 引用相等判斷
        if (obj == this) {
            return true;
        }
          // 型別判斷
        if (!(obj instanceof Building)) {
            return false;
        }
        Building building = (Building) obj;
          // 關鍵域相等判斷
        // 基本型別不要用用Objects.equals()方法,會自動裝箱帶來額外開銷
        return Objects.equals(name, building.name) && (area == building.area);
    }

    @Override
    public String toString() {
        return Objects.toString("name = " + name, "name is undefined") + ", "
                + Objects.toString("area = " + area, "area is undefined");
    }

      // setter、getter
}

3、toString

我們自己重寫toString方法時,有一點比較難寫,就是預設值設定。

// Objects.toString(Object o, String nullDefault)
public static String toString(Object o, String nullDefault) {
    return (o != null) ? o.toString() : nullDefault;
}

// Objects.toStirng(Object 0)
public static String toString(Object o) {
  return String.valueOf(o);
}

我們在重寫toString時,可以參考上面的Building類的寫法。

相關文章