国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - JAVA教程 - 深入理解Java中HashCode方法

深入理解Java中HashCode方法

2021-03-16 14:05御風逍遙 JAVA教程

這篇文章主要介紹了深入理解Java中HashCode方法,具有一定借鑒價值,需要的朋友可以參考下

關于hashCode,維基百科中:

?
1
2
3
4
In the Java programming language, every class implicitly or explicitly
provides a hashCode() method, which digests the data stored in an
instance of the class into a single hash value (a 32-bit signed
integer).

hashCode就是根據存儲在一個對象實例中的所有數據,提取出一個32位的整數,該整數的目的是用來標示該實例的唯一性。有點類似于MD5碼,每個文件都能通過MD5算法生成一個唯一的MD5碼。不過,Java中的hashCode并沒有真正的實現為每個對象生成一個唯一的hashCode,還是會有一定的重復幾率。

先來看看Object類,我們知道,Object類是java程序中所有類的直接或間接父類,處于類層次的最高點。在Object類里定義了很多我們常見的方法,包括我們要講的hashCode方法,如下

?
1
2
3
4
5
6
7
8
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
 return (this == obj);
public String toString() {
 return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

注意到hashCode方法前面有個native的修飾符,這表示hashCode方法是由非java語言實現的,具體的方法實現在外部,返回內存對象的地址。

在java的很多類中都會重寫equals和hashCode方法,這是為什么呢?最常見的String類,比如我定義兩個字符相同的字符串,那么對它們進行比較時,我想要的結果應該是相等的,如果你不重寫equals和hashCode方法,他們肯定是不會相等的,因為兩個對象的內存地址不一樣。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int hashCode() {
  int h = hash;
  if (h == 0) {
    int off = offset;
    char val[] = value;
    int len = count;
 
      for (int i = 0; i < len; i++) {
        h = 31*h + val[off++];
      }
      hash = h;
    }
    return h;
  }

其實這段代碼是這個數學表達式的實現

?
1
s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

s[i]是string的第i個字符,n是String的長度。那為什么這里用31,而不是其它數呢?《Effective Java》是這樣說的:之所以選擇31,是因為它是個奇素數,如果乘數是偶數,并且乘法溢出的話,信息就會丟失,因為與2相乘等價于移位運算。使用素數的好處并不是很明顯,但是習慣上都使用素數來計算散列結果。31有個很好的特性,就是用移位和減法來代替乘法,可以得到更好的性能:31*i==(i<<5)-i。現在的VM可以自動完成這種優化。

可以看到,String類是用它的value值作為參數來計算hashCode的,也就是說,相同的value就一定會有相同的hashCode值。這點也很容易理解,因為value值相同,那么用equals比較也是相等的,equals方法比較相等,則hashCode一定相等。反過來不一定成立。它不保證相同的hashCode一定有相同的對象。

一個好的hash函數應該是這樣的:為不相同的對象產生不相等的hashCode。

在理想情況下,hash函數應該把集合中不相等的實例均勻分布到所有可能的hashCode上,要想達到這種理想情形是非常困難的,至少java沒有達到。因為我們可以看到,hashCode是非隨機生成的,它有一定的規律,就是上面的數學等式,我們可以構造一些具有相同hashCode但value值不一樣的,比如說:Aa和BB的hashCode是一樣的。

如下代碼:

?
1
2
3
4
5
6
7
8
9
10
11
public class Main {
  public static void main(String[] args) {
    Main m = new Main();
    System.out.println(m);
    System.out.println(Integer.toHexString(m.hashCode()));
    String a = "Aa";
    String b = "BB";
    System.out.println(a.hashCode());
    System.out.println(b.hashCode());
  }
}

輸出結果:

?
1
2
3
4
Main@2a139a55
2a139a55
2112
2112

一般在重寫equal函數時,也要重寫hashCode函數,這是為什么呢?

來看看這個例子,讓我們創建一個簡單的類Employee

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Employee
{
  private Integer id;
  private String firstname;
  private String lastName;
  private String department;
 
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }
  public String getFirstname() {
    return firstname;
  }
  public void setFirstname(String firstname) {
    this.firstname = firstname;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public String getDepartment() {
    return department;
  }
  public void setDepartment(String department) {
    this.department = department;
  }
}

上面的Employee類只是有一些非常基礎的屬性和getter、setter.現在來考慮一個你需要比較兩個employee的情形。

?
1
2
3
4
5
6
7
8
9
10
11
public class EqualsTest {
  public static void main(String[] args) {
    Employee e1 = new Employee();
    Employee e2 = new Employee();
 
    e1.setId(100);
    e2.setId(100);
    //Prints false in console
    System.out.println(e1.equals(e2));
  }
}

毫無疑問,上面的程序將輸出false,但是,事實上上面兩個對象代表的是通過一個employee。真正的商業邏輯希望我們返回true。

為了達到這個目的,我們需要重寫equals方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public boolean equals(Object o) {
    if(o == null)
    {
      return false;
    }
    if (o == this)
    {
      return true;
    }
    if (getClass() != o.getClass())
    {
      return false;
    }
    Employee e = (Employee) o;
    return (this.getId() == e.getId());
}

在上面的類中添加這個方法,EauqlsTest將會輸出true。

So are we done?沒有,讓我們換一種測試方法來看看。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.HashSet;
import java.util.Set;
public class EqualsTest
{
    public static void main(String[] args)
      {
        Employee e1 = new Employee();
        Employee e2 = new Employee();
        e1.setId(100);
        e2.setId(100);
        //Prints 'true'
        System.out.println(e1.equals(e2));
        Set<Employee> employees = new HashSet<Employee>();
        employees.add(e1);
        employees.add(e2);
        //Prints two objects
        System.out.println(employees);
    }

上面的程序輸出的結果是兩個。如果兩個employee對象equals返回true,Set中應該只存儲一個對象才對,問題在哪里呢?

我們忘掉了第二個重要的方法hashCode()。就像JDK的Javadoc中所說的一樣,如果重寫equals()方法必須要重寫hashCode()方法。我們加上下面這個方法,程序將執行正確。

?
1
2
3
4
5
6
7
8
@Override
 public int hashCode()
 {
  final int PRIME = 31;
  int result = 1;
  result = PRIME * result + getId();
  return result;
 }

需要注意記住的事情

盡量保證使用對象的同一個屬性來生成hashCode()和equals()兩個方法。在我們的案例中,我們使用員工id。
eqauls方法必須保證一致(如果對象沒有被修改,equals應該返回相同的值)
任何時候只要a.equals(b),那么a.hashCode()必須和b.hashCode()相等。
兩者必須同時重寫。

總結

以上就是本文關于深入理解Java中HashCode方法的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

原文鏈接:http://blog.csdn.net/zhhtao89/article/details/50350247

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美一级二级三级 | 亚洲成人xxx| 99精品一区二区三区 | 国产在线第一页 | 特及毛片 | 偷拍一区二区三区 | 国产h片在线观看 | 中文字幕一二三区 | 成人亚洲精品 | av高清在线看 | 亚洲精品视频在线播放 | 国产999精品久久久久久 | 日韩精品专区在线影院重磅 | 国产成人精品免高潮在线观看 | 久久久精品亚洲 | 色综合欧美 | 欧美日韩三级在线 | 亚洲国产精品视频 | 日韩在线一区二区三区 | 国产成人精品亚洲日本在线观看 | 欧美激情一区 | 亚洲免费在线视频 | av中文字幕在线播放 | 久久精品久久综合 | 日韩成人av电影 | 色婷婷综合久久久中字幕精品久久 | 精品一区二区久久久久久久网站 | 国产精品亚洲视频 | 免费成人在线网站 | 亚洲国产一区视频 | 夜夜av| 欧洲一区二区三区 | 欧美亚洲在线 | 欧美黄色一区 | 免费又黄又爽又色的视频 | 中文字幕一区二区三区四区五区 | 亚洲精品久久久久久下一站 | 午夜精品久久久久久久久久久久久 | 国产毛片视频 | 国产综合视频 | 欧美 日韩 国产 一区 |