【问题标题】:How to compare sets without comparing the content如何在不比较内容的情况下比较集合
【发布时间】:2025-12-09 16:15:01
【问题描述】:

所以,我有两个集合,其中包含我的类 Capability 的元素。

public class Capability {
    private String name;

    public Capability(){
        //
    }

    public Capability(String name){
        this.name = name;
        //this.id = count.getAndIncrement();
    }

    public String getName(){
        return name;
    }


    @Override
    public String toString(){
        return "Capability: "+name+".";
    }
}

请忽略该类在字符串上的值,这是为了将来扩展。

我正在尝试比较从导入 json 文件得到的两个集合,所以它们不是同一个对象,也不包含相同的对象,只是具有相同的内容。

public boolean allCapabilitiesMet(){
        int count = 0;
        for(Capability taskCap : this.getReqCapabilities()){
            for(Capability primCap : this.getPrimitive().getCapabilities())
            {
                System.out.println(taskCap.equals(primCap));
                System.out.println(taskCap.getName().equals(primCap.getName()));
                if(taskCap.equals(primCap)){
                    count++;
                }
            }
        }
        return count == this.getReqCapabilities().size();
        //return this.getPrimitive().getCapabilities().containsAll(this.getReqCapabilities());
    }

目标是查看一个集合是否是另一个集合的子集,在我切换到从 json 文件导入之前,我可以使用注释返回来做到这一点。

问题是,我现在可以通过简单地将 if 子句更改为字符串比较来解决这个问题,因为这确实有效。一旦我开始向主类添加其他字段,这将是可怕的。

有什么办法可以在不手动检查内容的情况下比较集合内容吗?

【问题讨论】:

  • 您可能只是调整 Capability 类的 equals 方法。现在它应该包括 name 属性。如果您要向该类添加其他字段,只需将它们包含在 equals 方法中。您甚至不需要带有 count 变量的嵌套循环 - 您可以简单地使用 Set 的方法进行操作。
  • @juwil 我想完全避免 for 循环,只做类似 containsAll() 的事情。如果不可能,那么……
  • 这是可能的——但你必须为你的 Set 的成员实现 equals(和 hashcode btw.)。
  • 非常混乱:标题说“不比较内容”,但有问题“比较集合内容” ?!?
  • @user16320675 是的,抱歉,我的问题是如果可能的话,如何在不手动检查内容的情况下实现类似于return this.getPrimitive().getCapabilities().containsAll(this.getReqCapabilities()); 的东西。如果没有,我应该覆盖哪些方法

标签: java set comparison


【解决方案1】:

所以我只是在添加了一个 id 字段后替换了 Capability 中的 equals() 和 hashCode() 方法。

@Override
    public boolean equals(Object obj){
        if(this == obj)
            return true;
        
        if(obj == null || obj.getClass() != this.getClass())
            return false;
            
        Capability cap = (Capability) obj;
        return (cap.getName().equals(this.getName()) && cap.getId() == this.getId());    
    }

    @Override
    public int hashCode()
    {
        return (int) this.id;
    }

有了这个,我可以使用我最初计划用于比较的解决方案

public boolean allCapabilitiesMet(){
        return this.getPrimitive().getCapabilities().containsAll(this.getReqCapabilities());
    }

这个实现有什么问题吗?可悲的是,每次我想向 Capability 添加一个字段时,我都必须在 if 语句中添加一个术语。有没有其他办法?

【讨论】:

  • 首先有equals()和hashCode()contract。合同的要点之一是“如果两个对象相等,那么它们必须具有相同的哈希码”。在您的情况下,对于不相等的对象,hashCode 可以相同
  • hashCode 是在使用 HashSet 或 HashMap 时导入的。看看here
  • 为了使生成equals和hashCode的过程更容易,你可以使用project lombok @EqualsAndHashCode