【问题标题】:I'm getting ClassCastException even though I overriden compareTo() [closed]即使我覆盖了 compareTo() [关闭],我也会收到 ClassCastException
【发布时间】:2014-02-19 03:29:30
【问题描述】:

我收到 ClassCastException 错误。当我插入从我创建的类派生的对象时会发生此错误。 我的代码如下: 当我运行时,我总是收到 ClassCastException 错误。 此外,我的类的比较器在调试器中显示为 null。

我已经编写了一个比较器(据我所知)并重写了必要的方法。

如何将 Set 与我创建的类一起使用并使用 contains() 方法?

public class Person implements Comparable<Person>
{
    int age;
    double height;
    public Person(int age, double height)
    {
        this.age = age;
        this.height = height;
    }
    @Override
    public int compareTo(Person person) 
    {
        return age - person.age;
    }
    public boolean equals(Object obj)
    {
        final Person other = (Person) obj;
        if (this.age == other.age)
            return true;
        return false;
    }
    public static void main(String[] args)
    {
        Set<Person> people = new HashSet<>();
        Person p1 = new Person(10, 1.00);
        Person p2 = new Person(11, 1.10);
        Person p3 = new Person(12, 1.20);
        Person p4 = new Person(14, 1.40);
        people.add(p1);
        people.add(p2);
        people.add(p3);
        people.add(p4);
        if(people.contains(12))
            System.out.println("contains");
        else
            System.out.println("does not contain");
    }
}

我已经设法摆脱了这个错误。但是现在,输出是“不包含”。

【问题讨论】:

  • 你应该改变那个equals的实现,否则你会很糟糕......
  • 您究竟从哪里得到ClassCastException?错误信息是什么?
  • 当我尝试调用包含“相邻”对象的列表的 contains() 方法时,出现 ClassCastException。
  • 问题和原来写的完全不一样。我觉得people.contains(12)应该改成people.contains(p3)。
  • 你完全改变了问题的性质。您应该发布另一个(这不是一个坏问题)。长话短说,您不能在HashSet&lt;Person&gt; 上致电contains(int)。您确实需要将其包装在Person 中。包含将仅检查身份字段,因此“1.20”无关紧要。身份字段是您用于equals 和hashcode 的字段。

标签: java classcastexception comparator compareto


【解决方案1】:

我将要建议的内容与 ClassCastException 无关,它被抛出只是因为您在一组 Person 类型的对象上使用 int 参数检查 contains ... 简短回答:您不能将对象强制转换为它不是实例的子类。甚至the javadoc says exactly that。

对于这样的情况,我真的很喜欢使用 Guava 谓词。谓词允许您将布尔条件应用于任何可迭代对象,返回满足指定条件的那些元素。在您的示例中,您可以定义谓词来返回您想要的任何年龄的人的子集。

Predicate<Person> getAgePredicate(final int age) {
    return new Predicate<Person>() {
        public boolean apply(Person p) { return p.age == age; }
    };

}

Set<Person> people = new Hashset<>();
... // populate people
Set<Person> peopleOfAgeTwelve = Sets.filter(people, getAgePredicate(12));

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    我假设您的类 Adjacent 根据您的代码实现 Comparable 接口。你的类包含一个名为getID() 的方法。因此,因此当您覆盖 compareTo() 方法时,您需要确保对象比较有意义。我不确定您的 getID() 返回什么。但它似乎是整数。所以你可能想改变compareTo()的实现如下:

    @Override
    public int compareTo(Adjacent adj) {
    
        return this.getId() - adj.getId();
    }
    

    因此,这种比较将根据两个Adjacent 类对象的 ID 比较返回负数/零/正数。

    同样在您覆盖的equals() 方法中,实现不正确,因为两个对象不一定相等,即使它们具有相同的哈希码。在another SO post 中给出了覆盖equals 和hashCode 方法的一个很好的例子。另外,在您的情况下,我认为您可能甚至不需要覆盖 equals 方法,因为您的类已经实现了 Comparable 接口。

    【讨论】:

    • 这些都对 ClassCastException 没有帮助。
    • 如果没有引发异常的实际代码,我无法判断原因是什么。但这些是我可以从帖子中看到的问题可能来自的地方。
    • 不,这些问题不会导致 ClassCastException。 Stack Overflow 允许我们在问题下发布 cmets 的原因是,我们可以在 发布答案之前询问我们需要的实际信息,而不是反过来。
    【解决方案3】:

    不要使用不同类型的参数调用 contains;这种行为实际上是documented。由于遗留原因,contains() 方法是一种非泛型方法,如果您使用的是TreeSet,它是不安全的。如果你实现hashCode() 和equals() 并切换到HashSet,你的问题就会消失。

    你真的需要按年龄排序的人吗?

    编辑:我明白你现在想要做什么了。你不需要Set,你需要Map&lt;Integer, Collection&lt;Person&gt;&gt;,或者只需要一个循环来查找给定的年龄。

    for (Person p : people) {
        if (p.age == 12) ...;
    }
    

    或

    Map<Integer, Set<Person> peopleByAge = new HashMap<Integer, Set<Person>>();
    for (Person p : people) {
        if (!peopleByAge.contains(p.age)) {
            peopleByAge.put(p.age, new TreeSet<Person>();
        }
        peopleByAge.get(p.age).add(p);
    }
    
    if (people.age.containsKey(12)) ...
    

    【讨论】:

    • 我不需要对列表进行排序。我只是想看看有没有12岁的人。
    • 然后运行那个 for 循环。如果你要做很多,你会想要 Map。如果您需要 12 岁的所有人的列表,则需要第二个示例。
    • 我已经更新了这个问题。请检查。
    • 12 岁的人与 12 岁的整数不同。
    猜你喜欢
    • 2021-09-05
    • 1970-01-01
    • 2021-06-10
    • 2020-02-23
    • 1970-01-01
    • 2019-10-11
    • 2022-11-03
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多