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