【问题标题】:SortedMap with Comparator ClassCast Exception带有 Comparator ClassCast 异常的 SortedMap
【发布时间】:2013-01-12 13:48:19
【问题描述】:

为什么在覆盖的比较方法中在 (Person p2 = (Person) o2;) 处得到 ClassCastException。 :(

实际上,比较覆盖方法中的值不是 Person 对象,而是“Jim”和“Jack”(键值)。所以 Cast Cast Exception 。但是为什么它带有键而不是值,即 Person 对象,为什么它只适用于键。有没有其他方法可以根据值对其进行排序。

如有错误请指正

1) 我们可以在 TreeMap 中传递比较器对象,它会相应地对其进行排序。?

2) 总是在 Keys 上执行排序。 ?

3) 我们如何在不使用集合对象的情况下对 Map 的值进行排序(是否可能)以及为什么默认不支持?

公共类 HashTableExamples {

/**
 * @param args
 */
public static void main(String[] args) {

    SortedMap persorSorted = new TreeMap(new Comparator() {

        @Override 
        public int compare(Object o1, Object o2) {
            Person p2 = (Person) o2;
            return 2;
        }
    });

    Person p = new Person(10);
    Person p1 = new Person(20);
    persorSorted.put("Jim", p);
    persorSorted.put("Jack", p1);
    Iterator sortedit = persorSorted.entrySet().iterator();
    while (sortedit.hasNext()) {
        Map.Entry pairs = (Map.Entry) sortedit.next();
        Person pw = (Person) pairs.getValue();
        System.out.println("From SortedMap : " + pw.getAge());
    }
}

public static class Person {
    Person(int agevalue) {
        this.age = agevalue;
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

【问题讨论】:

  • 这就是 TreeMap 的作用。它按 keys 排序。有一些解决这个问题的黑客方法,包括将地图存储在比较器中。
  • 你应该在这里使用泛型,并创建一个合适的Comparator<String>。如果你正确使用泛型,这样的代码甚至不会编译。
  • @MattBall 很抱歉没有使用泛型,我只是在编写代码以根据值对其进行排序。我想即使我们使用泛型它也会失败,因为键是 String 。我只是想知道我的意思是为什么地图中的值有这种限制

标签: java sorting map sortedmap


【解决方案1】:

是的,TreeMap 总是按键排序。

至于为什么它不是“默认支持”——这是因为通常不存在有效支持它的数据结构。 任何编程语言都无法有效地支持它,因为Map 的目的是能够通过键查找内容,而按值排序意味着您不能 em> 以一种可以高效地通过键查找内容的方式组织数据。

如果您必须按值对Map 的条目进行排序,您可以使用如下方式:

List<Map.Entry<Foo, Bar>> entryList = 
  new ArrayList<Map.Entry<Foo, Bar>>(map.entrySet());
Collections.sort(entryList, new Comparator<Map.Entry<Foo, Bar>>() {
  public int compare(Map.Entry<Foo, Bar> entry1, Map.Entry<Foo, Bar> entry2) {
    return entry1.getValue().compareTo(entry2.getValue());
  }
});

或者,如果您愿意,如果您不控制值类型的实现,您可以使用替代比较器来比较值。

【讨论】:

  • 是的,我同意,但可能有很多场景中的值将是一个对象,我们想要对其进行排序。我想我可以为对象实现可比较并对其进行排序。但是如果我无权访问该对象怎么办:( .
  • 我已经添加了一些关于如何按值对Map 的条目进行排序的解释,但重点仍然存在——根本不可能编写一个对条目进行排序的高效Map 实现按价值计算,所以你必须以其他方式而不是使用Map
  • 是的,我知道使用集合实用程序排序方法根据值对其进行排序的解决方法。但我很好奇为什么 Map 的值没有比较器,或者为什么它仅限于键
  • 正如我在上面多次说过的,提供基于值排序的高效Map 实现是不可能或极其尴尬的。
  • 是的,这是有道理的“ Map 是为了能够通过它们的键来查找事物,而按值排序意味着您不能以一种使查找事物变得高效的方式来组织数据键”。嗯,好吧,我会去的。
【解决方案2】:

如果您查看documentation for TreeMap,您会看到它说:

构造一个新的空树映射,根据给定的比较器排序。插入到映射中的所有键必须通过给定的比较器相互比较:comparator.compare(k1, k2) 不能为映射中的任何键 k1 和 k2 抛出 ClassCastException。如果用户尝试将违反此约束的键放入映射中,则 put(Object key, Object value) 调用将抛出 ClassCastException。

这里的重点是比较 keys,但您将密钥(即:String)转换为 Person

【讨论】:

  • 是的,我能明白。但是为什么只允许键。是否有任何具体原因不允许它用于 values 。我的意思是我可以使用 List 作为值并对其进行排序,但是 .为什么要限制 Map 值。
  • 您应该查看@LouisWasserman 的答案以了解原因。我只是重复他说的话。但是,您可能能够做的事情(实际上取决于问题的领域)是将字符串 in 放入 Person 对象,然后使用 List 并按看起来在该字段的 Person 对象内。或者,您可以创建一个包含 nameperson 字段的临时类,然后对其中的 List 进行排序。
  • 是的,我知道基于 Values 对其进行排序的解决方法。但我的意思是,我知道这种解决方法。但我仍然不满意为什么它仅限于 keys 。也可能有许多场景中的值将是一个对象,我们想要对它进行排序。我想我可以为对象实现可比较并对其进行排序。但是如果我无权访问该对象怎么办:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-25
  • 2013-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
相关资源
最近更新 更多