不同的集合集合基于不同的equals / hashcode

时间:2014-11-12 08:11:09

标签: java

我希望根据Set / equals对同一种对象的不同实现,有两个hashCode个集合包含唯一对象。

例如,一个Set仅适用于具有不同时间戳的元素,而equals应返回a.timestamp!=b.timestamp,但另一个集合可能仅适用于具有不同的元素名称等于a.name!=b.name

有没有一种微不足道的方法来实现这一目标?如何为每个不同的Set制作自定义等号?

4 个答案:

答案 0 :(得分:1)

您的建议听起来像滥用equals方法和Set界面。

您的用例定义了两个类别,通过这两个类别可以对给定类型的对象进行分组(时间戳和名称),并且您希望有两个集合,每个集合最多为每个类别保留一个实例。

要做到这一点,拥有帮助器集会更有意义:

Set<String> timestamps;
Set<String> names;

然后,您可以为这些集添加名称和时间戳,并使用它们来检查是否应将对象添加到目标集合(不必是集合)。

例如:

List<SomeClass> timestampCategories = new ArrayList<SomeClass>();
List<SomeClass> nameCategories = new ArrayList<SomeClass>();
for (SomeClass object : inputCollection) {
    if (!timestamps.contains(object.getTimestamp()) {
        timestamps.add(object.getTimestamp());
        timestampCategories.add(object);
    }
    if (!names.contains(object.getName()) {
        names.add(object.getName());
        nameCategories.add(object);
    }
}

答案 1 :(得分:1)

创建两个包装值类,并将equalshashCode实现放在那里。

    public class Test {


    Set<NameBeanWrapper> names = new HashSet<Test.NameBeanWrapper>();
    Set<TimestampBeanWrapper> timestamps = new HashSet<Test.TimestampBeanWrapper>();

    public void store(Set<Bean> initial) {
      for (Bean bean : initial) {
        names.add(new NameBeanWrapper(bean));
        timestamps.add(new TimestampBeanWrapper(bean));
      }
    }

    public static class Bean {
      String name;
      Long timestamp;
      public String getName() {
        return name;
      }
      public void setName(String name) {
        this.name = name;
      }
      public Long getTimestamp() {
        return timestamp;
      }
      public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
      }
    }

    public static class NameBeanWrapper {
      final Bean bean;
      public NameBeanWrapper(Bean bean) {
        this.bean = bean;
      }
      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((bean == null || bean.name == null) ? 0 : bean.name.hashCode());
        return result;
      }
      @Override
      public boolean equals(Object obj) {
        if (this == obj) {
          return true;
        }
        if (obj == null) {
          return false;
        }
        if (getClass() != obj.getClass()) {
          return false;
        }
        NameBeanWrapper other = (NameBeanWrapper) obj;
        if (bean == null) {
          if (other.bean != null) {
            return false;
          }
        }else if (bean.name == null) {
            if (other.bean.name != null) {
              return false;
            }
        } else if (!bean.name.equals(other.bean.name)) {
          return false;
        }
        return true;
      }
    }

    public static class TimestampBeanWrapper {
      final Bean bean;
      public TimestampBeanWrapper(Bean bean) {
        this.bean = bean;
      }
      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((bean == null || bean.timestamp == null) ? 0 : bean.timestamp.hashCode());
        return result;
      }
      @Override
      public boolean equals(Object obj) {
        if (this == obj) {
          return true;
        }
        if (obj == null) {
          return false;
        }
        if (getClass() != obj.getClass()) {
          return false;
        }
        NameBeanWrapper other = (NameBeanWrapper) obj;
        if (bean == null) {
          if (other.bean != null) {
            return false;
          }
        }else if (bean.timestamp == null) {
            if (other.bean.timestamp != null) {
              return false;
            }
        } else if (!bean.timestamp.equals(other.bean.timestamp)) {
          return false;
        }
        return true;
      }
    }

  }

答案 2 :(得分:0)

正如所建议:

你想拥有同一个对象的两个列表吗?为什么不用你需要的所有属性创建一个父object然后实现两个对象,而不是从第一个继承不同的equals和hash?

答案 3 :(得分:0)

好的,我想知道是否有一种简单的方法可以指定要在Set中使用的equals / hashcode。我看到没有人听说过这样的事情。

如果无法做到这一点,我总是可以使用自定义哈希码作为键的Map,然后当我需要获取Collection时,我得到Map.values()。我想避免这种情况,因为要保持较低的内存使用率,但也许就是这样......