愿你如阳光,明媚不忧伤。
Hash 散列(哈希)就是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值(哈希码),是一种压缩映射。Hash算法可以将一个数据转换为一个标志,这个标志和源数据的每一个字节都有十分紧密的关系。Hash算法还具有一个特点,就是很难找到逆向规律。Hash算法虽然被称为算法,但实际上它更像是一种思想。Hash算法没有一个固定的公式,只要符合散列思想的算法都可以被称为是Hash算法。注意:equals相同,则hashCode相同;而hashCode相同,equals不一定相同(可能会发生散列碰撞)。
*****************************************************************
@HotSpotIntrinsicCandidate
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
................................................................
public int hashCode() {
int lockWord = shadow$_monitor_;
final int lockWordStateMask = 0xC0000000; // Top 2 bits.
final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash).
final int lockWordHashMask = 0x0FFFFFFF; // Low 28 bits.
if ((lockWord & lockWordStateMask) == lockWordStateHash) {
return lockWord & lockWordHashMask;
}
//返回的是对象引用地址
return System.identityHashCode(this);
}
*****************************************************************
*****************************************************************
/* 如果进行过hash计算,或者字符串的长度为0 ,不进行hash计算
与16进制数0xff(二进制1111 1111 占一个字节)按位与运算,只有两个位同时为1,才能得到1
经过计算后得到一个整数数值。
*/
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
hash = h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
}
return h;
}
................................................................
// StringLatin1中的hashCode方法(单字节编码)
public static int hashCode(byte[] value) {
int h = 0;
for (byte v : value) {
h = 31 * h + (v & 0xff);
}
return h;
}
// StringUTF16中的hashCode方法(双字节编码,UTF8是变长编码)
public static int hashCode(byte[] value) {
int h = 0;
int length = value.length >> 1;
for (int i = 0; i < length; i++) {
h = 31 * h + getChar(value, i);
}
return h;
}
................................................................
・【模拟hash计算】
String name = "God";
value = {
'G', 'o', 'd'};
hash = 0;
value.length = 3;
//执行逻辑:
val = value;
val[0] = "G";
val[1] = "o";
val[2] = "d";
h = 31 * 0 + G = G;
h = 31 * (31 * 0 + G) + o = 31 * G + o;
h = 31 * (31 * (31 * 0 + G) + o) + d = 31 * 31 * G + 31 * o + d;
推导出数学公式:val[0]*31^(n-1) + val[1]*31^(n-2) + ... + val[n-1]
至于为什么是31?因为31的二进制是11111
*****************************************************************
// 如果引用地址一样,则返回true;如果地址不一样,则挨个比较他们的字节码,也就是比较字符的内容。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
................................................................
// StringLatin1中的equals方法(单字节编码)
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
// StringUTF16中的equals方法(双字节编码,UTF8是变长编码)
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
int len = value.length >> 1;
for (int i = 0; i < len; i++) {
if (getChar(value, i) != getChar(other, i)) {
return false;
}
}
return true;
}
return false;
}
*****************************************************************
*****************************************************************
@HotSpotIntrinsicCandidate
public static int hashCode(int value) {
return value;
}
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
*****************************************************************
*****************************************************************
package com.it.god.entity;
public class HashApple {
private String color;
private String shape;
private Double gram;
// 重写equals方法
@Override
public boolean equals(Object obj) {
if (!(obj instanceof HashApple)) {
return false;
}
HashApple happle = (HashApple) obj;
if (this == happle) {
return true;
}
if (happle.shape.equals(this.shape) && happle.gram.equals(this.gram)) {
return true;
} else {
return false;
}
}
public HashApple(String color, String shape, Double gram) {
super();
this.color = color;
this.shape = shape;
this.gram = gram;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public Double getGram() {
return gram;
}
public void setGram(Double gram) {
this.gram = gram;
}
}
*****************************************************************
package com.it.god.controller;
import com.it.god.entity.HashApple;
public class HashAppleController {
public static void main(String[] args) {
HashApple ha1 = new HashApple("red", "circle", 200.86);
HashApple ha2 = new HashApple("green", "circle", 200.86);
if (ha1.equals(ha2)) {
System.out.println("ha1与ha2两个苹果是一样的");
} else {
System.out.println("ha1与ha2两个苹果不一样");
}
}
}
................................................................
・【CONSOLE】结果
ha1与ha2两个苹果是一样的
*****************************************************************
*****************************************************************
public class HashAppleController {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
HashApple ha1 = new HashApple("red", "circle", 200.86);
HashApple ha2 = new HashApple("green", "circle", 200.86);
if (ha1.equals(ha2)) {
System.out.println("ha1与ha2两个苹果是一样的");
} else {
System.out.println("ha1与ha2两个苹果不一样");
}
@SuppressWarnings("rawtypes")
Set set = new HashSet();
set.add(ha1);
set.add(ha2);
System.out.println(set);
}
}
................................................................
・【CONSOLE】结果
ha1与ha2两个苹果是一样的
[com.it.god.entity.HashApple@73a28541, com.it.god.entity.HashApple@5aaa6d82]
*****************************************************************
*****************************************************************
// 重写hashcode方法
@Override
public int hashCode() {
int result = shape.hashCode();
result = 17 * result + gram.hashCode();
return result;
}
................................................................
・【CONSOLE】结果
ha1与ha2两个苹果是一样的
[com.it.god.entity.HashApple@fc89d439]
*****************************************************************
不同关键字通过相同哈希计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。
例如一个hash算法为mod3对3取模运算,5mod3=2,8mod3=2,这就是哈希碰撞。