代码之家  ›  专栏  ›  技术社区  ›  Samrudh S

即使值和插入顺序相同,使用equals函数比较映射值也会返回false

  •  0
  • Samrudh S  · 技术社区  · 1 年前

    我有两个Map对象:一个 HashMap 还有一个 LinkedHashMap 两者都包含相同的值(例如[1,2]),并且对于 LinkedHashMap ,插入顺序得以保留。但是,当我使用equals()方法比较这些映射的values()函数返回的集合时,比较返回false。

    我最初认为这可能是由于 哈希图 不保持插入顺序。但当我对两个进行相同的比较时 LinkedHashMap 对象,其中插入顺序确实得以保留 equals() 方法仍然返回false。

    有人能解释一下为什么 equals() 方法在这两种情况下都返回false,即使:

    • 这些值的内容是相同的([1,2]),
    • 在以下情况下,值的顺序得以保留 LinkedHashMap ?
    import java.util.LinkedHashMap;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Main {
        public static void main(String[] args) {
    
            // HashMap example
    
            Map<String, Integer> map1 = new HashMap<>();
            map1.put("a", 1);
            map1.put("b", 2);
    
            Map<String, Integer> map2 = new HashMap<>();
            map2.put("x", 1);
            map2.put("y", 2);
    
            System.out.println("map1 values: " + map1.values());  // prints [1, 2]
            System.out.println("map2 values: " + map2.values());  // prints [1, 2]
    
            System.out.println("map1.values().equals(map2.values()): " + map1.values().equals(map2.values())); // returns false
    
    
            // LinkedHashMap example
    
            Map<String, Integer> map1l = new LinkedHashMap<>();
            map1l.put("a", 1);
            map1l.put("b", 2);
    
            Map<String, Integer> map2l = new LinkedHashMap<>();
            map2l.put("x", 1);
            map2l.put("y", 2);
    
            System.out.println("map1l values: " + map1l.values()); // prints [1, 2]
            System.out.println("map2l values: " + map2l.values()); // prints [1, 2]
    
            System.out.println("map1l.values().equals(map2l.values()): " + map1l.values().equals(map2l.values())); // still returns false
        }
    }
    
    2 回复  |  直到 1 年前
        1
  •  4
  •   dani-vta    1 年前

    两个实例返回集合的原因 HashMap 被认为是不相等的,即使它们以相同的顺序包含相同的元素,也是因为实际实现 Collection 返回由 HashMap.values() 是一个内部类 哈希图 打电话 Values ,它没有提供正确的定义 equals() 方法。

    HashMap$Values 继承其定义 equals() 方法从 Object 类,它只将当前对象的内存地址与给定的参数进行比较。因此,由于该方法比较驻留在两个不同内存地址中的两个不同对象,因此该方法返回 false .

    当你比较你返回的集合时,也会发生同样的事情 LinkedHashMap 实例。不过,在这种情况下,您正在比较以下两个实例 LinkedHashMap$LinkedValues 没有提供正确的定义 equals() 同时,继承了其定义 对象 .

        2
  •  2
  •   VGR    1 年前

    从面向对象的角度来看: Map.values() returns a Collection ,而且绝对有 no guarantees about two Collections being equal.

    集合的子类(列表和集合) 有这样的保证,但如果你有两个对象是集合,但不能保证它们是列表或集合,那么无论它们的元素是什么,都不能保证它们会被视为相等的。

    当然,您可以轻松地将它们转换为Set:

    Set<?> values1 = Set.copyOf(map1.values());
    Set<?> values2 = Set.copyOf(map2.values());
    System.out.println("values equal: " + values1.equals(values2));
    

    但是,请注意,集合不能有重复的值,因此虽然这适用于您的示例,但它不会考虑多个键存在相同值的贴图。为了处理这个问题,您可以创建排序列表:

    List<Integer> values1 = new ArrayList<>(map1.values());
    List<Integer> values2 = new ArrayList<>(map2.values());
    values1.sort(null);
    values2.sort(null);
    System.out.println("values equal: " + values1.equals(values2));
    
        3
  •  1
  •   WJS    1 年前

    如果你这样做

    System.out.println(map1l.values().getClass().getSimpleName());
    

    它打印

    LinkedValues
    

    查看源代码,该类定义为

    final class LinkedValues extends AbstractCollection<V> implements 
         SequencedCollection<V> {
    

    该类层次结构中没有任何内容是覆盖的 equals 继承自 Object 因此,唯一需要比较的是每个收藏的参考文献。为了正确地比较它们,你可以这样做。

    System.out.println(new ArrayList<>(map1l.values()).equals(new ArrayList<>(map2l.values())));
    

    打印 true

    使用IDE,如 Eclipse 有助于解释在其他情况下没有意义的事情,因为您可以跟踪API代码的实现细节。否则,您可以直接检查源代码。

    一个洞穴: 这个 Objects 在每个集合中,必须覆盖equals,否则您将再次只是比较引用。

        4
  •  -3
  •   王新趠   1 年前

    因为map1-map2是不同的实例,它们有自己的地址。

    值:

       public Collection<V> values() {
            Collection<V> vs = values;
            if (vs == null) {
                vs = new Values();
                values = vs;
            }
            return vs;
        }
    new instancetwo实例不相等