【Java 没基础之 Guava 用户指南个人翻译】—— Hashing

本文是关于Guava库中Hashing模块的个人翻译和解析,介绍了HashFunction、Hasher、Funnel和HashCode等概念,以及它们在处理哈希算法时的角色。文章还探讨了BloomFilter的使用,它是概率数据结构,用于判断元素是否存在。同时,文章提供了Guava中内置的哈希函数,如Murmur3的32位和128位实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

Guava 是非常棒的 Java 核心类库,其中各种工具类比如集合框架、图形库、工具类、字符串工具类、缓存技术等实现要优于Java本身的一部分代码。
于是我在业余时间开始结合网上资料加上我自己使用时的一些理解,翻译用户指南并完成一部分优秀代码的中文解析。
不求对别人多大帮助,只求查缺补漏

【Java 没基础——Guava用户指南】Hashing (哈希)

Overview (概述)

Java 的 HashCode 的长度被限制在 32 位,并且哈希算法与他们作用的数据(类或方法)之间没有分离,
因此很难使用另外的哈希算法进行替换。同时,Java 内建的哈希算法生成的 Hash 值是十分劣质的,有一部分原因是因为他们依赖于劣质的 Hashcode 实现,其中包括很多 JDK 中的实现类。

Java 中 Object.hashCode 运行十分快速,但是缺乏对 哈希碰撞 问题的预防,同时也缺乏对散列值的期望。这种特性却让他十分适合与应用在哈希表中,因为额外的哈希碰撞只会
带来很小的性能损失,同时十分差劲的分散性可以采用二次哈希的方法解决(Java 中几乎所有
合理的哈希算法(哈希函数)都采用这种方法进行实现)。然而,在简单哈希表之外的很多哈希应用中,
Object.hashCode却是不足的,因此com.google.common.hash包被设计出来。

Organization (组成)

通过查看包的 Java doc 文档, 我们会发现很多不同的类,但是并没有明显的说明他们是如何协同工作的。

让我们先看一下这个类库的一部分代码:

HashFunction hf = Hashing.md5();
HashCode hc = hf.newHasher()
       .putLong(id)
       .putString(name, Charsets.UTF_8)
       .putObject(person, personFunnel)
       .hash();
HashFunction (哈希方法–生成Hash值的方法)

[HashFunction] 是一个对引用透明的、无状态(无返回值)的方法,他把任意的数据块映射到固定长度的地址中,
尽量确保相同的输入一定产生相同的输出,不同的输入产生不同的输出。

Hasher (哈希对象)

一个 HashFunciton 可以提供一个有状态的 [Hasher],它提供了可以将输入数据十分快速的计算出哈希值的方法。
Hasher 可以接受任何形式的数据,byte arrays(字节数组)、slices of byte arrays(字节数组的片段)、character squences(特定字符集的字符序列)等等,
或者是任何一个提供了 Funnel 实现的对象。

Hasher 实现了 PrimitiveSink 接口,为 一个接受原生数据类型的流的对象 定义了 fluent 风格的 API。

Funnel

一个 [Funnel] 描述了如何将一个确定的对象分解为原生字段值。比如,我们有这样一个对象:

class Person {
  final int id;
  final String firstName;
  final String lastName;
  final int birthYear;
}

我们的 Funnel 可能看起来像这样

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);
  }
};

注: putString("abc", Charsets.UTF_8).putString("def", Charsets.UTF_8) 等同于 putString("ab", Charsets.UTF_8).putString("cdef",
Charsets.UTF_8)
, 因为他们生成相同的字节序列。这可能导致意料之外的 Hash冲突,
增加某种形式的分隔符有助于减少 Hash冲突。

HashCode

一旦 Hasher 拿到了所有的输入值, 他就可以调用 [hash()] 方法得到一个 [HashCode] 实例。
HashCode 支持平等性检测,比如 [asInt()], [asLong()], [asBytes()] 方法等,此外,
[writeBytesTo(array, offset, maxLength)] 方法支持将哈希值前 maxLength 长度的字节写入到数组中。

// 注:writeBytesTo 方法在 Guava 中如此定义: 
@CanIgnoreReturnValue
public int writeBytesTo(byte[] dest, int offset, int maxLength)
/**
解释:
    将 Hash code 的字节串拷贝到目标数组中
参数:
    dest - 将被字节数组写入的位置
    offset - 数据起始位
    maxLength - 字节数组的最大写入长度
返回值:
    int 写入到目标位置的字节数
*/

BloomFilter (一个过滤器)

Bloom filters 是哈希运算的一个优雅的运用, 不能简单的采用 Object.hashCode() 来实现。
简而言之,BloomFilter 是一个概率数据结构, 允许你测试一个对象一定不在这个过滤器中,
或者他可能已经存在与里面。对此,BloomFilter 的维基页面 进行了相当详细的解释,
同时这里推荐一个关于BloomFilter 的 教程

Guava 的哈希类库中有个内建的 BloomFilter 实现, 只需要你提供一个 Funnel 的实现类,就能将他分解为原始类型。
你可以通过 [create(Funnel funnel, int
expectedInsertions, double falsePositiveProbability)
] 方法来获取一个 [BloomFilter<T>] 对象,
缺省误检率只有 3%。 BloomFilter<T> 提供了 [boolean mightContain(T)] 和 [void put(T)] 方法,
他们的功能显而易见。

BloomFilter<Person> friends = BloomFilter.create(personFunnel, 500, 0.01);
for (Person friend : friendsList) {
  friends.put(friend);
}
// 很久之后... 
if (friends.mightContain(dude)) { // 如果 dude 可能包括在 friends 中
  // dude 不是一个 friend(Person 的实现) 并且还运行到这里的概率为 1%
  // 我们可以在这对 dude 进行精确检查的同时进行一些异步加载。
}

Hashing

Hashing 提供了很多的哈希函数,和对 HashCode 对象进行操作运算的工具方法。

Provided Hash Functions(提供的Hash函数)

  • [md5()]
  • [murmur3_128()] 使用零值种子返回一个 murmur3 算法实现的 128 位的哈希值
  • [murmur3_32()] 使用零值种子返回一个 murmur3 算法实现的 32 位的哈希值
  • [sha1()] 被 Google 破解的安全哈希算法
  • [sha256()]
  • [sha512()]
  • [goodFastHash(int bits)] 返回一个多用途的,临时使用的,非加密的 Hash Function.

HashCode Operations 算法

方法名描述
[HashCode combineOrdered(Iterable<HashCode>)]以有序的方式使 HashCode 结合起来,如果两个 HashCode 集合采用此种方法结合后的 HashCode 相同,那么这两个 HashCode 集合中的元素可能是顺序相等的。
[HashCode combineUnordered(Iterable<HashCode>)]以无序的方式使 HashCode 结合起来,如果两个 HashCode 集合采用此方法结合后的 HashCode 相同,那么这两个 HashCode 集合中的元素可能在某种排序方式下是顺序相等的。
[int consistentHash(HashCode, int buckets)]以给定 buckets 的大小分配一致性哈希,最大限度的减少随 buckets 增长而进行重新映射的需要.了解详情 一致性哈希 Wikipedia

后记:我将所有内容都发布在 Github 上,您可以加入我们,也可以提出问题共同讨论,下面是我Github 的项目地址:【guava-jch】
~如果能点个 star 就更好了

下面的公众号里有美丽的小姐姐
我们公众号二维码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值