【问题标题】:How to make enums use their compareTo method when they implement an interface?如何让枚举在实现接口时使用它们的 compareTo 方法?
【发布时间】:2015-04-08 16:48:45
【问题描述】:

结构是这样的:

public interface ItemList{ }

public enum ItemList1 implements ItemList {

    Apple,
    Orange;
}

public enum ItemList2 implements ItemList {

    Banana,
    Grapes;
}

还有 5 个这样的枚举

要求是在地图中使用这些枚举作为键,在这些地图中,我将键设置为:

public Class SomeClass {
private Map<ItemList, OtherObject> objectList;
//other code
}

进入地图的 ItemList 是在运行时决定的。而且我需要使用像 TreeMap 这样的排序 Map 来进行其他操作。 因此,TreeMap 显然无法比较键枚举,因为我已将它们声明为 ItemList 超类型。

所以,我搜索了其他问题并做了类似的事情,以便枚举可以使用他们的 compareTo 方法:

public interface ItemList<SelfType extends ItemList<SelfType>> extends Comparable<SelfType>{ }

public enum ItemList1 implements ItemList<SelfType> {
     //enum values
}

但这并不能解决问题。当我尝试检索将我的枚举作为键的 TreeMap 时,我仍然得到相同的“ClassCastException”。

如果我在这里做错了什么,请提出建议,或者有什么其他方法可以解决这个目的?

编辑: 链接到我遵循的解决方案,但它不起作用: How to implement an interface with an enum, where the interface extends Comparable?

编辑 2 发现问题。对不起大家。 我的地图被填充了不同类型的枚举作为键,当所有键都应该属于相同类型才能进行排序时。

【问题讨论】:

  • 我不明白为什么地图无法对键进行排序。只要它只包含 ItemList1 的实例,或只包含 ItemList2 的实例,一切都应该正常工作。而且从你的描述来看,好像是这样的。
  • 您不能将来自两个不同枚举的常量作为键放在一个 TreeMap 中。基本上你无法比较它们。
  • @JBNizet 是的,同样的事情困扰着我。我检查了很多次。我关注了这个问题的答案stackoverflow.com/questions/7160980/…
  • @RohitJain 地图只填充了一种类型的列表。但是,它将填充哪个枚举是在运行时决定的。
  • @AnmolGupta 那你就得不到ClassCastException

标签: java interface enums comparable


【解决方案1】:

好吧,您已经发现是 Map 的实际内容,而不是导致异常的类的声明,但值得注意的是,使用集合比较这些 enums 比您想象的要容易.

例如TreeMap 不关心其声明的 Generic 类型是否具有可比较的键。如果你有类似的类声明

public interface ItemList{ }
public enum ItemList1 implements ItemList { Apple, Orange }
public enum ItemList2 implements ItemList { Banana, Grapes }

你可以简单地使用它

TreeMap<ItemList,Object> tm=new TreeMap<>();
tm.put(ItemList1.Apple, "A");
tm.put(ItemList1.Orange, "O");
System.out.println(tm.get(ItemList1.Apple)+" is for "+ItemList1.Apple);
tm.clear();
tm.put(ItemList2.Banana, "B");
tm.put(ItemList2.Grapes, "G");
System.out.println(tm.get(ItemList2.Banana)+" is for "+ItemList2.Banana);

没有问题;如果您将地图声明为TreeMap&lt;Object,Object&gt;,它甚至可以工作。

请注意,通过不指定Comparator,请求自然顺序时,某些方法需要可比较的类型,例如使用上面的类型声明,

List<Object> list=Arrays.<Object>asList(ItemList1.Orange,ItemList1.Apple,ItemList1.Orange);
Collections.sort(list);

不编译,但是,您可以通过nullComparator 请求自然顺序轻松绕过它:

Collections.sort(list, null); // compiles and works

因此,在大多数情况下,没有必要处理复杂的类型声明,例如 ItemList&lt;SelfType extends ItemList&lt;SelfType&gt;&gt;

【讨论】:

  • 感谢 Holger,这增加了我使用 TreeMap 的知识。只是为了确保我正确地得到它,所以每当我没有树图键的特定比较器时,它会在排序时采用自然顺序吗?对于需要明确提及比较器的方法,我可以将 null 作为比较器传递给自然顺序仍被视为排序顺序吗?谢谢!
  • 对,不指定 Comparator 总是意味着自然排序,并且省略参数的重载通常强制执行 Comparable 元素,而采用 Comparator 的方法则不这样做。我不能说出所有可能的方法,但 Collections.sortCollections.binarySearch 的文档清楚地指定了 null 比较器的行为。
【解决方案2】:

听起来你应该做的是拥有

 private Map<? extends ItemList, OtherObject> objectList;

...表示objectListItemList的某个子类型的特定映射,然后

 objectList = new TreeMap<ItemList1, OtherObject>();

 objectList = new TreeMap<ItemList2, OtherObject>();

将其声明为某种特定类型的ItemList。 (您可能需要在填充时将其临时存储为Map&lt;ItemListN, OtherObject&gt;,但随后您可以将其放入objectList

【讨论】:

  • 感谢 Louis 的快速响应,问题是 Map 在某个点上填充了不同类型的枚举,我要求它比较苹果和香蕉,所以它抛出了异常 :)
猜你喜欢
  • 1970-01-01
  • 2014-07-11
  • 2013-05-11
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 2020-11-28
相关资源
最近更新 更多