You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Java中Protobuf对象与普通类对象在Set中的行为存在差异?

Protobuf vs 普通Java类在Set中去重的差异解析

咱们先把问题拆解清楚:为什么用Protobuf生成的类创建值相同的对象,放进HashSet里会自动去重,而普通Java类做不到?这背后其实是Java集合的去重逻辑,加上Protobuf生成类的特殊实现导致的。


先看普通Java类的问题

你写的NodeJava类默认继承自Object,而Object类的equals()和hashCode()都是基于对象的内存地址工作的:

  • equals():只有两个引用指向同一个对象时才返回true
  • hashCode():返回的是和对象内存地址相关的数值

所以每次你new NodeJava("localhost", 12346),都会在堆里创建一个新对象,内存地址完全不一样。HashSet判断元素重复的逻辑是:先对比hashCode()是否相等,若相等再调用equals()确认。这两个新对象的hashCode()不同,equals()也返回false,HashSet就会把它们当成不同元素,最终输出的size是3。

要是想让普通类也能去重,你得手动重写这两个方法,让它们基于字段值来判断:

import java.util.Objects;

public class NodeJava {
    private String host;
    private Integer port;

    public NodeJava(String host, Integer port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        NodeJava nodeJava = (NodeJava) o;
        return Objects.equals(host, nodeJava.host) && Objects.equals(port, nodeJava.port);
    }

    @Override
    public int hashCode() {
        return Objects.hash(host, port);
    }
}

改完之后再运行相同的代码,HashSet就能识别出值相同的元素,size会变成2。


再看Protobuf类的特殊之处

Protobuf生成的Java类,天生就解决了这个问题,核心有两点:

1. 自动生成基于字段的equals()和hashCode()

Protobuf编译器在生成Java类时,会根据你定义的消息字段(比如host和port)自动生成equals()和hashCode()方法。举个例子,NodeProto的equals()会逐字段比较host和port的实际值,hashCode()会把这两个字段的值组合起来计算哈希码。

这意味着,哪怕是两个不同的实例,只要字段值完全一样,equals()就返回true,hashCode()也相同,HashSet会认为它们是同一个元素,自然会去重。

2. 可选的实例池化优化

你提到的“创建值相同的新对象时返回同一个对象”,是Protobuf的一个性能优化——实例池化。当你调用Builder的build()方法时,Protobuf会先检查内部缓存里有没有字段值完全相同的实例,如果有,就直接返回那个实例,而不是创建新对象。

比如你两次调用create("localhost", 12346),第二次build()会发现已经有一个一模一样的实例,直接复用它,所以两个引用指向同一个对象。不过要注意:就算没有这个池化机制,只要equals()和hashCode()正确,HashSet依然会去重——池化只是减少了对象创建的开销,不是去重的必要条件。


核心差异总结

对比项普通Java类(未重写方法)Protobuf生成类
equals()判断逻辑比较对象内存地址比较所有字段的实际值
hashCode()计算逻辑基于内存地址生成基于所有字段的值计算哈希码
对象创建策略每次new生成新实例值相同时可能复用已有实例(池化)
HashSet去重效果无法去重自动去重

内容的提问来源于stack exchange,提问作者Sudheesh Singanamalla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:08:15