TreeSet的比较器无法正常工作

时间:2013-07-02 15:44:54

标签: java comparator treeset

我的想法是按层分类一些实体(只是一些整数)。我发现有人似乎有同样的问题(我认为),但我不明白解决方案。 每个实体的层存储在一个数组中。我对图层使用了一个enumaration。

public enum Layer {
DEFAULT,
BACKGROUND,
FOREGROUND,
HUD_0,
HUD_1
}

所以我不知道我是否误解了比较器的工作方式,或者我是否因为实体是整数而遇到问题......

final Layer[] layers = {Layer.BACKGROUND, Layer.HUD_1, Layer.DEFAULT, Layer.DEFAULT, Layer.HUD_0, Layer.HUD_1};
    TreeSet<Integer> sorted = new TreeSet<Integer>(new Comparator<Integer>() {
        @Override
        public int compare(Integer entity1, Integer entity2) {
            //Integer layer1 = layers[entity1].ordinal();
            //Integer layer2 = layers[entity2].ordinal();
            //return layer1 < layer2 ? -1 : (layer1 > layer2 ? 1 : 0);
            return layers[entity1].compareTo(layers[entity2]);
        }
    });
    sorted.add(0);//bg
    System.out.println(sorted.toString());
    sorted.add(4);//hud0
    System.out.println(sorted.toString());
    sorted.add(2);//def
    System.out.println(sorted.toString());
    sorted.add(3);//def
    System.out.println(sorted.toString());
    sorted.add(1);//hud1
    System.out.println(sorted.toString());
    sorted.add(5);//hud1
    System.out.println(sorted.toString());

这是输出:

[0]
[0, 4]
[2, 0, 4]
[2, 0, 4]
[2, 0, 4, 1]
[2, 0, 4, 1]

最后一个应该是[2,3,0,4,1,5]

我读到一个TreeSet只存储一个元素,因为它是一个Set但是我不知道为什么它使用了那个层而不是我真正想要插入的实体。

3 个答案:

答案 0 :(得分:3)

从TreeSet的角度来看,如果item1.compareTo(item2) == 0,则两个元素相等。在您的情况下,Layer.HUB_1在您的数组中出现两次,两个项目将被视为相等,因此只会添加一个。

答案 1 :(得分:2)

这种情况就是这样,因为这就是TreeSet的定义方式:“TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此从集合的角度来看,这个方法认为相同的两个元素是,平等。“ java.util.TreeSet

你可以引入一个在同一层中的不同对象之间强加一个顺序的连接断路器 - 如果你没有什么更有意义的话,它可以只是一个任意的序列号。不同层中的对象仍将按层排序。

答案 2 :(得分:0)

问题最终是TreeSet(只是一个集合)只保存一次元素,它需要一种方法来知道它是否已经包含一个元素,并且它使用你提供的Comparator来做到这一点。由于您的比较器使用枚举进行排序,因此如果枚举匹配,则Treeset看到两个条目相同。

有关详细信息,请参阅http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html,尤其是段落

  

请注意,如果要正确实现Set接口,则由set维护的排序(无论是否提供显式比较器)必须与equals一致。 (有关与equals一致的精确定义,请参阅Comparable或Comparator。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此从集合的角度来看,通过这种方法被认为相等的元素是相等的。集合的行为即使其排序与equals不一致也是明确定义的;它只是不遵守Set接口的一般合同。

最终,如果您想使用TreeSet对枚举进行排序,那么当枚举匹配时,您需要扩展比较逻辑以回退其他内容。像

这样的东西
public int compare(Integer entity1, Integer entity2) {
    int returnValue = layers[entity1].compareTo(layers[entity2]);
    if(returnValue == 0){
        returnValue = entity1.compareTo(entity2);
    }
}

然后只是因为枚举匹配而使实体不匹配(并且无法添加到TreeSet中)。