2017-06-16 46 views
3

我试图来覆盖提到的方法我HashSet如何重写equals(),hashCode()和的compareTo()对于一个HashSet

Set<MyObject> myObjectSet = new HashSet<MyObject>(); 

为MyObject:

public class MyObject implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    Long id; 
    String name; 
    int number; 
    Map<String,String> myMap; 

    public MyObject(String name, int number, Map<String,String> myMap) { 
    this.name = name; 
    this.number = number; 
    this.myMap = myMap; 
    } 

    [...] 
} 

如何覆盖hashcode(),equals()和compareTo()方法?


目前,我有以下几点:

public int hashCode() { 
    return id.hashCode(); 
} 

// override the equals method. 
public boolean equals(MyObject s) { 
    return id.equals(s.id); 
} 

// override compareTo 
public int compareTo(MyObject s) { 
    return id.compareTo(s.id); 
}  

,我读了由ID比较是不够的,这是对象是一个数据库中的持久性实体(见here)。

该类型的所有对象的名称和编号都不唯一。

那么我该如何重写它呢?
我还需要比较它里面的hashMap吗?

我很困惑。关于对象唯一的独特之处是地图myMap,它在生命周期的后期被填充。

如何检查其是否相等?

基于所有的回答,我已经改变了方法,下面

@Override 
    public boolean equals(final Object o) { 
    if (this == o) return true; 
    if (o == null || getClass() != o.getClass()) return false; 

    final MyComplexObj myComplexObj = (MyComplexObj) o; 

    return myMap != null ? myMap.equals(myComplexObj.myMap) : myComplexObj.myMap == null; 
    } 

    @Override 
    public int hashCode() { 
    return myMap != null ? myMap.hashCode() : 0; 
    } 



    public int compareTo(MyComplexObj o) { 
    return myMap.compareTo(o.getMyMap())); 
    } 

这未能在compareTo方法“,该方法是不确定的类型映射

+0

正如你所提到的,关于对象唯一的独特之处是地图中的第一个条目,我会考虑添加一个额外的域,并在其中复制该条目。这样它将成为真实世界的候选关键字,并可用于实现equals和hashcode方法。你能不能详细说明这个对象的生命周期?当这些方法实际上会被调用? – Hassan

+2

我们没有足够的信息来回答你的问题。该ID从哪里来?我在MyObject中看不到ID。你的实体在数据库中的主要关键是什么? –

+3

正如现在写的,这个问题是非常不清楚的。你的代码重写的例子是错误的(因为他们使用equals()的错误参数类型)。然后你使用的是一个没有在MyObject类中定义的id字段?你应该把重点放在首先改善问题上,而不是提供赏金。 – GhostCat

回答

0

这里的基本问题是“如何确定两个对象是否相等?”

这是简单对象的一个​​简单问题。然而,即使稍微复杂的对象也变得越来越困难。

正如原来的问题说:

有关对象的唯一独特的东西是地图MYMAP其获取生命周期后填充。

给定MyObject类型的两个实例,成员变量myMap必须相互比较。该地图类型为Map<String, String>。几个问题立刻浮现在脑海中:

  • 键值&值如何定义相等?
    • (没有一个键值对需要比较作为一个单元?)
    • (或只应的值来相互比较?)
  • 地图上的按键顺序如何影响相等性?
    • (应在列表中的键进行排序,使ABC相当于BCA?)
    • (或不1-2-3意味着什么比3-2-1不同?)
  • 大写/小写是否与值的相等有所不同?
  • 这些物体是否会被储存在某种Java HashSetJava TreeSet
    • (你需要多次存储相同对象的相同集合中?)
    • (或应该具有相同散列码的对象只存储一次?)
  • 将这些对象永远需要整理作为列表的一部分或Java Collection
  • 比较函数应该如何在列表中排列不等于对象?
    • (应该怎么按键的顺序确定对象是否将显示在列表更早或更晚来的?)
    • (数值应如何确定顺序,特别是如果几个值有什么不同?)

这些问题中的每一个的答案会因应用程序而异。为了这个应用让一般读者,以下假设被提出:

  • 要保持确定性的比较,钥匙将被分拣
  • 值将被认为是区分大小写的
  • 键和值是分不开的,并且将作为一个单元
  • 在地图将被展平为一个单一的字符串进行比较,这样的结果可以容易地

使用的美相比,hashCode()compareTo()是一旦hashCode()正确实施,其他功能可以基于hashCode()定义。

考虑到所有这一切,我们有以下的实现:

@Override 
public boolean equals(final Object o) 
{ 
    if (o instanceof MyObject) 
    { 
     return (0 == this.compareTo(((MyObject) o))); 
    } 
    return false; 
} 

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

// Return a negative integer, zero, or a positive integer 
// if this object is less than, equal to, or greater than the other object 
public int compareTo(final MyObject o) 
{ 
    return this.hashCode() - o.hashCode(); 
} 

// The Map is flattened into a single String for comparison 
private static String getKeyValuePairs(final Map<String, String> m) 
{ 
    final StringBuilder kvPairs = new StringBuilder(); 

    final String kvSeparator = "="; 
    final String liSeparator = "^"; 

    if (null != m) 
    { 
     final List<String> keys = new ArrayList<>(m.keySet()); 
     Collections.sort(keys); 

     for (final String key : keys) 
     { 
      final String value = m.get(key); 
      kvPairs.append(liSeparator); 
      kvPairs.append(key); 
      kvPairs.append(kvSeparator); 
      kvPairs.append(null == value ? "" : value); 
     } 
    } 

    return 0 == kvPairs.length() ? "" : kvPairs.substring(liSeparator.length()); 
} 

所有关键工作正在的hashCode()内部完成。为了排序,compareTo()函数只需要返回一个负数/零/正数 - 一个简单的hashCode()差异。而equals()函数只需要返回true/false - 一个简单的检查,compareTo()等于零。


对于进一步的阅读,有逻辑的基础著名的对话刘易斯·卡罗尔,这倒是平等的基本问题:

https://en.wikipedia.org/wiki/What_the_Tortoise_Said_to_Achilles

而且,对于即使是简单的语法结构,在chapter 6, "Pig and Pepper"开始处有两个“相等”的句子,从Alice in Wonderland

鱼足先生从他的胳膊下面开始写了一封很棒的信,然后他交给另一个人,用严肃的语气说道:“对于公爵夫人。女王邀请玩槌球。“青蛙仆人用同样严肃的口吻重复道,”从女王。对于公爵夫人邀请她去玩槌球。”然后他们俩都深深地鞠了一躬他们的假发缠在一起了。

1

这是什么的IntelliJ默认选项给

import java.util.Map; 

public class MyObject { 
    String name; 
    int number; 
    Map<String,String> myMap; 

    @Override 
    public boolean equals(final Object o) { 
    if (this == o) return true; 
    if (o == null || getClass() != o.getClass()) return false; 

    final MyObject myObject = (MyObject) o; 

    if (number != myObject.number) return false; 
    if (name != null ? !name.equals(myObject.name) : myObject.name != null) return false; 
    return myMap != null ? myMap.equals(myObject.myMap) : myObject.myMap == null; 
    } 

    @Override 
    public int hashCode() { 
    int result = name != null ? name.hashCode() : 0; 
    result = 31 * result + number; 
    result = 31 * result + (myMap != null ? myMap.hashCode() : 0); 
    return result; 
    } 
} 

但是,既然你说

关于对象唯一的独特之处在于地图myMap,它在生命周期的较后阶段获取 。

我只想保持MYMAP和跳过这两者的名称和号码(不过这引出了一个问题,为什么你会在你的收藏中的所有元素包括一个冗余数据 - 姓名和电话号码?)

然后它成为

import java.util.Map; 

public class MyObject { 
    String name; 
    int number; 
    Map<String,String> myMap; 

    @Override 
    public boolean equals(final Object o) { 
    if (this == o) return true; 
    if (o == null || getClass() != o.getClass()) return false; 

    final MyObject myObject = (MyObject) o; 

    return myMap != null ? myMap.equals(myObject.myMap) : myObject.myMap == null; 
    } 

    @Override 
    public int hashCode() { 
    return myMap != null ? myMap.hashCode() : 0; 
    } 
} 

请记住,有太多的equals和hashCode方法的其他方式。例如,下面是的IntelliJ给出了代码生成

enter image description here

要回答另一个问题有关的CompareTo

不像equals和hashCode,这里是没有合同的compareTo和任何其他行为之间存在的各种选择。你不需要对compareTo做任何事情,直到你想用它来说,排序。阅读更多关于CompareTo Why should a Java class implement comparable?

+0

谢谢,要试试这个。那么compareTo方法呢? –

+0

对象的唯一性在于它的地图,不仅仅是第一个条目,我做了更改 –

+0

@user_mda你用compareTo来做什么?排序?那么我会推迟到lambda流和排序。 –

0

compareTo()与排序有关。它与HashSetHashMap无关。

适当的工作equals()hashCode()对基于散列的集合的成员至关重要。阅读他们在Javadoc的规格Object

实现这些的最终建议可能在Joshua Bloch的Effective Java。我建议阅读相关章节 - 它很容易通过Google进行。在这里试图解释这一切没有意义。可能已经逃脱了您的通知


一两件事,是你的领域myMap有工作equals()和自身的hashCode(),所以你没有做什么特别的。如果你能保证没有任何字段为空,合理hashCode()会(以下布洛赫的系统):

public int hashCode() { 
    int result = 44; // arbitrarily chosen 
    result = 31 * result + (int) (id^(id >>> 32)); 
    result = 31 * result + name.hashCode(); 
    result = 31 * result + number; 
    result = 31 * result + myMap.hashCode(); 
    return result; 
} 

(你会需要更多的代码,如果任何一个可能为null)


几乎所有IDE将自动生成equals()hashcode(),使用该类中的所有字段。他们会使用与Bloch的建议非常相似的内容。在用户界面周围狩猎。你会找到它。

另一种方法是使用Apache ReflectionUtils,它允许您只需使用:

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

@Override 
public boolean equals(final Object obj) { 
    return EqualsBuilder.reflectionEquals(this, obj); 
} 

这工作了哪些字段在运行时使用,并适用布洛赫的方法。

+0

一个downvote和一个删除请求,评论为什么....? – slim

0

如果你想myMap实现媲美,而且所需的任何其他方法,创建实现可比装饰接口和委托其他方法来封闭myMap实例。

public class ComparableMap implements Map<String, String>, Comparable<Map<String, String>> { 
    private final Map<String, String> map; 

    public ComparableMap(Map<String, String> map) { 
     this.map = map; 
    } 

    @Override 
    public int compareTo(Map<String, String> o) { 
     int result = 0; 
     //your implementation based on values on map on you consider one map bigger, less or as same as another 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return map.equals(obj); 
    } 

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

    // map implementation methods 

    @Override 
    public int size() { 
     return map.size(); 
    } 

    @Override 
    public boolean isEmpty() { 
     return map.isEmpty(); 
    } 

    @Override 
    public boolean containsKey(Object key) { 
     return map.containsKey(key); 
    } 

    @Override 
    public boolean containsValue(Object value) { 
     return map.containsValue(value); 
    } 

    @Override 
    public String get(Object key) { 
     return map.get(key); 
    } 

    @Override 
    public String put(String key, String value) { 
     return map.put(key, value); 
    } 

    @Override 
    public String remove(Object key) { 
     return map.remove(key); 
    } 

    @Override 
    public void putAll(Map<? extends String, ? extends String> m) { 
     map.putAll(m); 
    } 

    @Override 
    public void clear() { 
     map.clear(); 
    } 

    @Override 
    public Set<String> keySet() { 
     return map.keySet(); 
    } 

    @Override 
    public Collection<String> values() { 
     return map.values(); 
    } 

    @Override 
    public Set<Entry<String, String>> entrySet() { 
     return map.entrySet(); 
    } 

} 

您可以使用此图中的任何地方,你用myMap

public class MyObject implements Serializable { 

     private static final long serialVersionUID = 1L; 

     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     Long id; 
     String name; 
     int number; 
     ComparableMap myMap; 

     public MyObject(String name, int number, Map<String, String> myMap) { 
      this.name = name; 
      this.number = number; 
      this.myMap = new ComparablemyMap(myMap); 
     } 


     @Override 
     public boolean equals(final Object o) { 
      if (this == o) return true; 
      if (o == null || getClass() != o.getClass()) return false; 

      final MyComplexObj myComplexObj = (MyComplexObj) o; 

      return myMap != null ? myMap.equals(myComplexObj.myMap) : myComplexObj.myMap == null; 
     } 

     @Override 
     public int hashCode() { 
      return myMap != null ? myMap.hashCode() : 0; 
     } 


     public int compareTo(MyComplexObj o) { 
      return myMap.compareTo(o.getMyMap())); //now it works 
     } 

    } 
相关问题