? ? ? ?Guava Hash(散列)指的是通過某種算法把數(shù)據(jù)源通過一系列的轉(zhuǎn)換生成一串字符串儡湾。常見的例如hash code生成眼溶,加密字符的生成授药,檢驗(yàn)字符的生成等等具滴。接下來我們就對Guava Hash(散列)的使用做一個(gè)介紹凹嘲。使用很簡單。Guava Hash(散列)里面也給我們提供了很多hash算法构韵。已經(jīng)能滿足我們大部分需求了周蹭。
一 Hash(散列)介紹
? ? ? ?Hash里面比較重要的類有:Hashing、HashFunction疲恢、Hasher凶朗、HashCode、Funnel显拳、PrimitiveSink棚愤。
1.1 Hashing
? ? ? ?Hashing類是一個(gè)幫助類,里面提供的方法都是根據(jù)不同的hash算法生成對應(yīng)的HashFunction對象杂数。每個(gè)hash算法都實(shí)現(xiàn)了HashFunction宛畦。Hashing類里面提供的方法如下。
- [ goodFastHash(int minimumBits) ]: 返回一個(gè)多用途的揍移,臨時(shí)使用的次和,非加密的 Hash Function
- [ murmur3_32(int seed) ]: 使用指定參數(shù)值做種子返回一個(gè) murmur3 算法實(shí)現(xiàn)的 32 位的哈希值
- [ murmur3_32() ]: 使用零值種子返回一個(gè) murmur3 算法實(shí)現(xiàn)的 32 位的哈希值
- [ murmur3_128() ]: 使用零值種子返回一個(gè) murmur3 算法實(shí)現(xiàn)的128位的哈希值。
- [ sipHash24() ]: sipHash24 加密算法
- [ sipHash24(long k0, long k1) ]: sipHash24 加密算法
- [ md5() ]: md5 加密算法那伐。
- [ sha1() ]:sha1算法踏施,hash。
- [ sha256() ]: sha256 加密算法
- [ sha384() ]: sha384 加密算法
- [ sha512() ]: sha512 加密算法
- [ hmacMd5(Key key) ]: hmacMd5 加密算法
- [ hmacMd5(byte[] key) ]:hmacMd5 加密算法
- [ hmacSha1(Key key) ]:hmacSha1 加密算法
- [ hmacSha1(byte[] key) ]:hmacSha1 加密算法
- [ hmacSha256(Key key) ]:hmacSha256 加密算法
- [ hmacSha256(byte[] key) ]:hmacSha256 加密算法
- [ hmacSha512(Key key) ]:hmacSha512 加密算法
- [ hmacSha512(byte[] key) ]:hmacSha512 加密算法
- [ crc32c() ]:CRC32C 校驗(yàn)算法
- [ crc32() ]:CRC-32 校驗(yàn)算法
- [ adler32() ]:Adler-32 校驗(yàn)算法
- [ farmHashFingerprint64() ]
- [ consistentHash(HashCode hashCode, int buckets) ]:以給定 buckets 的大小分配一致性哈希罕邀,最大限度的減少隨 buckets 增長而進(jìn)行重新映射的需要读规。
- [ consistentHash(long input, int buckets) ]
- [ combineOrdered(Iterable<HashCode> hashCodes) ]:以有序的方式使 HashCode 結(jié)合起來,如果兩個(gè) HashCode 集合采用此種方法結(jié)合后的 HashCode 相同燃少,那么這兩個(gè) HashCode 集合中的元素可能是順序相等的束亏。
- [ combineUnordered(Iterable<HashCode> hashCodes) ]: 以無序的方式使 HashCode 結(jié)合起來,如果兩個(gè) HashCode 集合采用此方法結(jié)合后的 HashCode 相同阵具,那么這兩個(gè) HashCode 集合中的元素可能在某種排序方式下是順序相等的碍遍。
- [ concatenating(HashFunction first, HashFunction second, HashFunction... rest) ]: 將多個(gè)hash值拼接在一起定铜。比如你想要1024位的一個(gè)hash,你就可以Hashing.concatenating(Hashing.sha512(), Hashing.sha512())
1.2 HashFunction
? ? ? ?HashFunction有兩個(gè)作用:創(chuàng)建Hasher對象怕敬、也可以直接根據(jù)輸入條件返回HashCode結(jié)果揣炕。HashFunction里面常用函數(shù)如下:
public interface HashFunction {
/**
* 獲取一個(gè)Hasher
*/
Hasher newHasher();
Hasher newHasher(int expectedInputSize);
/**
* 根據(jù)input生成HashCode
*/
HashCode hashInt(int input);
HashCode hashLong(long input);
HashCode hashBytes(byte[] input);
HashCode hashBytes(byte[] input, int off, int len);
HashCode hashBytes(ByteBuffer input);
HashCode hashUnencodedChars(CharSequence input);
HashCode hashString(CharSequence input, Charset charset);
/**
* 根據(jù)一個(gè)對象生成HashCode
*/
<T> HashCode hashObject(T instance, Funnel<? super T> funnel);
/**
* 返回此哈希生成的每個(gè)哈希代碼的位數(shù)(32的倍數(shù))
*/
int bits();
}
1.3 Hasher
? ? ? ?Hasher的主要作用是根據(jù)加入的數(shù)據(jù)源得到HashCode。數(shù)據(jù)源通過提供的putXxx()方法添加东跪、hash()方法返回計(jì)算結(jié)果HashCode畸陡。
public interface Hasher extends PrimitiveSink {
/**
* 添加產(chǎn)生HashCode的數(shù)據(jù)源
*/
@Override
Hasher putByte(byte b);
@Override
Hasher putBytes(byte[] bytes);
@Override
Hasher putBytes(byte[] bytes, int off, int len);
@Override
Hasher putBytes(ByteBuffer bytes);
@Override
Hasher putShort(short s);
@Override
Hasher putInt(int i);
@Override
Hasher putLong(long l);
@Override
Hasher putFloat(float f);
@Override
Hasher putDouble(double d);
@Override
Hasher putBoolean(boolean b);
@Override
Hasher putChar(char c);
@Override
Hasher putUnencodedChars(CharSequence charSequence);
@Override
Hasher putString(CharSequence charSequence, Charset charset);
/**
* 添加一個(gè)對象數(shù)據(jù)源
*/
<T> Hasher putObject(T instance, Funnel<? super T> funnel);
/**
* 獲取到HashCode
*/
HashCode hash();
}
1.4 HashCode
? ? ? ?HashCode是對結(jié)果的一個(gè)封裝。
public abstract class HashCode {
/**
* 返回此HashCode中的位數(shù); 8的正數(shù)倍虽填,注意哦是bit
*/
public abstract int bits();
/**
* 把HashCode的前面四個(gè)字節(jié)轉(zhuǎn)換為int(小端順序排列)
*
* @throws IllegalStateException if {@code bits() < 32}
*/
public abstract int asInt();
/**
* 把HashCode的前面八個(gè)字節(jié)轉(zhuǎn)換為long(小端順序排列)
*
* @throws IllegalStateException if {@code bits() < 64}
*/
public abstract long asLong();
/**
* 如果HashCode位數(shù)足夠多按照asLong()函數(shù)處理丁恭,不夠直接轉(zhuǎn)換為long
*/
public abstract long padToLong();
/**
* HashCode以byte[]形式返回,字節(jié)數(shù)組的形式輸出
*/
// TODO(user): consider ByteString here, when that is available
public abstract byte[] asBytes();
/**
* HashCode放到dest里面去,并且返回放入的返回長度
*/
@CanIgnoreReturnValue
public int writeBytesTo(byte[] dest, int offset, int maxLength);
/**
* 把int轉(zhuǎn)換為32位長度的HashCode
*/
public static HashCode fromInt(int hash);
/**
* 把long轉(zhuǎn)換為64位長度的HashCode
*/
public static HashCode fromLong(long hash);
/**
* 把byte數(shù)組轉(zhuǎn)換為HashCode
*/
public static HashCode fromBytes(byte[] bytes);
/**
* String轉(zhuǎn)換為HashCode
*/
public static HashCode fromString(String string);
/**
* 返回hash code對應(yīng)的字符串
*/
@Override
public final String toString();
}
五 Funnel斋日、PrimitiveSink
? ? ? ?定義了怎樣將一個(gè)Object對象里面的各個(gè)屬性放到PrimitiveSink里面牲览,Hasher的putObject方法需要傳入這樣的對象。
Funnel
public interface Funnel<T> extends Serializable {
/**
* Sends a stream of data from the {@code from} object into the sink {@code into}. There is no
* requirement that this data be complete enough to fully reconstitute the object later.
*
* @since 12.0 (in Guava 11.0, {@code PrimitiveSink} was named {@code Sink})
*/
void funnel(T from, PrimitiveSink into);
}
PrimitiveSink
public interface PrimitiveSink {
/**
* 把參數(shù)放到PrimitiveSink里面去
*/
PrimitiveSink putByte(byte b);
PrimitiveSink putBytes(byte[] bytes);
PrimitiveSink putBytes(byte[] bytes, int off, int len);
PrimitiveSink putBytes(ByteBuffer bytes);
PrimitiveSink putShort(short s);
PrimitiveSink putInt(int i);
PrimitiveSink putLong(long l);
PrimitiveSink putFloat(float f);
PrimitiveSink putDouble(double d);
PrimitiveSink putBoolean(boolean b);
PrimitiveSink putChar(char c);
PrimitiveSink putUnencodedChars(CharSequence charSequence);
PrimitiveSink putString(CharSequence charSequence, Charset charset);
}
? ? ? ?使用實(shí)例
Funnel<Person> personFunnel = new Funnel<Person>() {
@Override
public void funnel(Person person, PrimitiveSink into) {
into
.putInt(person.id)
.putString(person.firstName, Charsets.UTF_8)
.putString(person.lastName, Charsets.UTF_8)
.putInt(birthYear);
}
}
二 Hash(散列)使用實(shí)例
2.1 各種算法對應(yīng)的hash code
// 各種算法對應(yīng)的hash code
String input = "hello, world";
// MD5
System.out.println(Hashing.md5().hashBytes(input.getBytes()).toString());
// sha256
System.out.println(Hashing.sha256().hashBytes(input.getBytes()).toString());
// sha512
System.out.println(Hashing.sha512().hashBytes(input.getBytes()).toString());
// crc32
System.out.println(Hashing.crc32().hashBytes(input.getBytes()).toString());
// MD5
System.out.println(Hashing.md5().hashUnencodedChars(input).toString());
2.2 多個(gè)數(shù)據(jù)源對應(yīng)的hash code
HashFunction hf = Hashing.md5();
HashCode hc = hf.newHasher()
.putLong(10)
.putString("abc", Charsets.UTF_8)
.hash();
System.out.println(hc.toString());
2.3 數(shù)據(jù)源是對象的情況
@Test
public void objectToHashCode() {
// 需要hash的對象
Person person = new Person(27, "wu", "xing", 1990);
Funnel<Person> personFunnel = new Funnel<Person>() {
@Override
public void funnel(Person person, PrimitiveSink into) {
into
.putInt(person.id)
.putString(person.firstName, Charsets.UTF_8)
.putString(person.lastName, Charsets.UTF_8)
.putInt(person.birthYear);
}
};
// md5算法
HashFunction hf = Hashing.md5();
HashCode hc = hf.newHasher()
.putString("abc", Charsets.UTF_8)
.putObject(person, personFunnel)
.hash();
System.out.println(hc.toString());
}
class Person {
int id;
String firstName;
String lastName;
int birthYear;
public Person(int id, String firstName, String lastName, int birthYear) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.birthYear = birthYear;
}
}
? ? ? ?Guava Hash(散列)的使用很簡單吧恶守,首先在Hashing找到我們對應(yīng)需要的hash算法(一般里面的這些hash算法能滿足我們絕大部分的情況)第献。然后把數(shù)據(jù)源put進(jìn)去,如果有多個(gè)數(shù)據(jù)源依次put進(jìn)去就可以了兔港。最后hash()就得到了我們最終hash的結(jié)果了庸毫。