Java 在列表、布尔映射中存储值时出现比较错误

Java 在列表、布尔映射中存储值时出现比较错误,java,swing,Java,Swing,我有一个用Java实现的扫雷舰的完整工作版本。但是,我正在尝试添加一个附加功能,用于更新地图,以在二维数组中存储矿山位置的索引。例如,如果位置[x][y]中有地雷,我将存储一个包含x和y的链表,该链表映射到一个布尔值,该布尔值为true,表示该空间中有地雷。(这个特性看起来微不足道,但我这样做只是为了在Java中练习集合。) 我的相关私有实例变量包括: public Class World{ ... private LinkedList<Integer> index; priv

我有一个用Java实现的扫雷舰的完整工作版本。但是,我正在尝试添加一个附加功能,用于更新地图,以在二维数组中存储矿山位置的索引。例如,如果位置[x][y]中有地雷,我将存储一个包含x和y的链表,该链表映射到一个布尔值,该布尔值为true,表示该空间中有地雷。(这个特性看起来微不足道,但我这样做只是为了在Java中练习集合。)

我的相关私有实例变量包括:

public Class World{ ...

private LinkedList<Integer>  index;

private Map<LinkedList<Integer>, Boolean> revealed;
没有标记的添加组件,我的程序运行良好,我有一个完全正常工作的游戏。但是,这个添加给了我以下错误

Exception in thread "main" java.lang.ClassCastException: java.util.LinkedList 
cannot be cast to java.lang.Comparable

如果有人能帮助指出这个错误可能在哪里,那将是非常有帮助的!这仅用于集合的额外练习,不需要运行游戏。

树形图的规范给了我以下信息:

映射根据其键的自然顺序进行排序,或者由映射创建时提供的比较器进行排序,具体取决于使用的构造函数


Java Linkedlist不能像那样进行比较。你必须给它一种比较它们的方法,或者只使用另一种类型的地图,这不需要排序。

这里实际上有三个问题。一个是你知道的,一个是你不知道的,第三个是使用
LinkedList
作为地图的键很笨重

  • 之所以出现
    ClassCastException
    ,是因为它是一个排序集,需要其中的每个键实现
    Comparable
    接口,否则必须提供一个自定义
    比较器
    LinkedList
    没有实现可比较的
    Compariable
    ,因此您会得到一个异常。这里的解决方案可以是使用不同的映射,如
    HashMap
    ,也可以编写自定义的
    比较器。

    自定义的
    比较器可以如下所示:

    revealed = new TreeMap<List<Integer>, Boolean>(
        // sort by x value first
        Comparator.comparing( list -> list.get(0) )
            // then sort by y if both x values are the same
            .thenComparing( list -> list.get(1) )
    );
    
    Map<Integer, Map<Integer, Boolean>> revealed = new HashMap<>();
    {
        revealed.computeIfAbsent(x, HashMap::new).put(y, true);
        // the preceding line is the same as saying
        // Map<Integer, Boolean> yMap = revealed.get(x);
        // if (yMap == null) {
        //     yMap = new HashMap<>();
        //     revealed.put(x, yMap);
        // }
        // yMap.put(y, true);
    }
    
    这是未指定的行为,因为您将密钥放入,然后对其进行修改。
    Map
    的文档对此作了如下说明:

    注意:如果将可变对象用作贴图键,则必须非常小心。如果对象是贴图中的关键点时,对象的值以影响
    等于
    比较的方式更改,则不会指定贴图的行为

    实际发生的情况(对于
    TreeMap
    )是您总是在擦除以前的映射。(例如,第一次调用
    put
    ,比方说
    x=0
    y=0
    。然后下一次,您将列表设置为
    x=1
    y=1
    。这也会修改映射内的列表,以便在调用
    put
    时,它会发现已经有一个带有
    x=1
    y=1的键。)
    并替换映射。)

    因此,您可以通过以下方式解决此问题:

     private void placeBomb(){
            int x = ran.nextInt(worldWidth);     //Random stream
            int y = ran.nextInt(worldHeight);    //Random stream
    
                if (!tileArr[x][y].isBomb()){
                    tileArr[x][y].setBomb(true);
    
                    index.add(x);                //ADDED COMPONENT
                    index.add(y);
                    revealed.put(index, true);
                    index.remove(x);
                    index.remove(y);             //END OF ADDED COMPONENT
    
    
                } else placeBomb();
    
        }
    
    // copying the List called index
    revealed.put(new LinkedList<>(index), true);
    // this makes more sense to me
    revealed.put(Arrays.asList(x, y), true);
    
    //复制名为index的列表
    discovered.put(新链接列表(索引),true);
    //这对我来说更有意义
    discovered.put(Arrays.asList(x,y),true);
    
    然而,这就引出了第三点

  • 如果您想练习集合,有更好的方法可以做到这一点。一种方法是使用
    地图
    ,如下所示:

    revealed = new TreeMap<List<Integer>, Boolean>(
        // sort by x value first
        Comparator.comparing( list -> list.get(0) )
            // then sort by y if both x values are the same
            .thenComparing( list -> list.get(1) )
    );
    
    Map<Integer, Map<Integer, Boolean>> revealed = new HashMap<>();
    {
        revealed.computeIfAbsent(x, HashMap::new).put(y, true);
        // the preceding line is the same as saying
        // Map<Integer, Boolean> yMap = revealed.get(x);
        // if (yMap == null) {
        //     yMap = new HashMap<>();
        //     revealed.put(x, yMap);
        // }
        // yMap.put(y, true);
    }
    
    Map discovered=newhashmap();
    {
    exposed.computeIfAbsent(x,HashMap::new).put(y,true);
    //前一行和下面这句话是一样的
    //Map yMap=discovered.get(x);
    //if(yMap==null){
    //yMap=newhashmap();
    //显示。put(x,yMap);
    // }
    //yMap.put(y,true);
    }
    
    这基本上类似于2D数组,但使用的是
    HashMap
    。(如果你有一个非常非常大的游戏板,这是有道理的。)

    从你的描述来看,听起来你已经知道你只需要做一个
    布尔值就可以了平铺
    类中的code>变量

  • Map<Integer, Map<Integer, Boolean>> revealed = new HashMap<>();
    {
        revealed.computeIfAbsent(x, HashMap::new).put(y, true);
        // the preceding line is the same as saying
        // Map<Integer, Boolean> yMap = revealed.get(x);
        // if (yMap == null) {
        //     yMap = new HashMap<>();
        //     revealed.put(x, yMap);
        // }
        // yMap.put(y, true);
    }