Guava Hash(散列)指的是通过某种算法把数据源通过一系列的转换生成一串字符串。常见的例如hash code生成,加密字符的生成,检验字符的生成等等。接下来我们就对Guava Hash(散列)的使用做一个介绍。使用很简单。Guava Hash(散列)里面也给我们提供了很多hash算法。已经能满足我们大部分需求了。
一 Hash(散列)介绍
Hash里面比较重要的类有:Hashing、HashFunction、Hasher、HashCode、Funnel、PrimitiveSink。
1.1 Hashing
Hashing类是一个帮助类,里面提供的方法都是根据不同的hash算法生成对应的HashFunction对象。每个hash算法都实现了HashFunction。Hashing类里面提供的方法如下。
- [ goodFastHash(int minimumBits) ]: 返回一个多用途的,临时使用的,非加密的 Hash Function
- [ murmur3_32(int seed) ]: 使用指定参数值做种子返回一个 murmur3 算法实现的 32 位的哈希值
- [ murmur3_32() ]: 使用零值种子返回一个 murmur3 算法实现的 32 位的哈希值
- [ murmur3_128() ]: 使用零值种子返回一个 murmur3 算法实现的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 校验算法
- [ crc32() ]:CRC-32 校验算法
- [ adler32() ]:Adler-32 校验算法
- [ farmHashFingerprint64() ]
- [ consistentHash(HashCode hashCode, int buckets) ]:以给定 buckets 的大小分配一致性哈希,最大限度的减少随 buckets 增长而进行重新映射的需要。
- [ consistentHash(long input, int buckets) ]
- [ combineOrdered(Iterable<HashCode> hashCodes) ]:以有序的方式使 HashCode 结合起来,如果两个 HashCode 集合采用此种方法结合后的 HashCode 相同,那么这两个 HashCode 集合中的元素可能是顺序相等的。
- [ combineUnordered(Iterable<HashCode> hashCodes) ]: 以无序的方式使 HashCode 结合起来,如果两个 HashCode 集合采用此方法结合后的 HashCode 相同,那么这两个 HashCode 集合中的元素可能在某种排序方式下是顺序相等的。
- [ concatenating(HashFunction first, HashFunction second, HashFunction... rest) ]: 将多个hash值拼接在一起。比如你想要1024位的一个hash,你就可以Hashing.concatenating(Hashing.sha512(), Hashing.sha512())
1.2 HashFunction
HashFunction有两个作用:创建Hasher对象、也可以直接根据输入条件返回HashCode结果。HashFunction里面常用函数如下:
public interface HashFunction {
/**
* 获取一个Hasher
*/
Hasher newHasher();
Hasher newHasher(int expectedInputSize);
/**
* 根据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);
/**
* 根据一个对象生成HashCode
*/
<T> HashCode hashObject(T instance, Funnel<? super T> funnel);
/**
* 返回此哈希生成的每个哈希代码的位数(32的倍数)
*/
int bits();
}
1.3 Hasher
Hasher的主要作用是根据加入的数据源得到HashCode。数据源通过提供的putXxx()方法添加、hash()方法返回计算结果HashCode。
public interface Hasher extends PrimitiveSink {
/**
* 添加产生HashCode的数据源
*/
@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);
/**
* 添加一个对象数据源
*/
<T> Hasher putObject(T instance, Funnel<? super T> funnel);
/**
* 获取到HashCode
*/
HashCode hash();
}
1.4 HashCode
HashCode是对结果的一个封装。
public abstract class HashCode {
/**
* 返回此HashCode中的位数; 8的正数倍,注意哦是bit
*/
public abstract int bits();
/**
* 把HashCode的前面四个字节转换为int(小端顺序排列)
*
* @throws IllegalStateException if {@code bits() < 32}
*/
public abstract int asInt();
/**
* 把HashCode的前面八个字节转换为long(小端顺序排列)
*
* @throws IllegalStateException if {@code bits() < 64}
*/
public abstract long asLong();
/**
* 如果HashCode位数足够多按照asLong()函数处理,不够直接转换为long
*/
public abstract long padToLong();
/**
* HashCode以byte[]形式返回,字节数组的形式输出
*/
// 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转换为32位长度的HashCode
*/
public static HashCode fromInt(int hash);
/**
* 把long转换为64位长度的HashCode
*/
public static HashCode fromLong(long hash);
/**
* 把byte数组转换为HashCode
*/
public static HashCode fromBytes(byte[] bytes);
/**
* String转换为HashCode
*/
public static HashCode fromString(String string);
/**
* 返回hash code对应的字符串
*/
@Override
public final String toString();
}
五 Funnel、PrimitiveSink
定义了怎样将一个Object对象里面的各个属性放到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 {
/**
* 把参数放到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);
}
使用实例
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(散列)使用实例
2.1 各种算法对应的hash code
// 各种算法对应的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 多个数据源对应的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 数据源是对象的情况
@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找到我们对应需要的hash算法(一般里面的这些hash算法能满足我们绝大部分的情况)。然后把数据源put进去,如果有多个数据源依次put进去就可以了。最后hash()就得到了我们最终hash的结果了。
网友评论