HashMap get返回时为空,即使其中有密钥



我正在尝试创建一个带有图标的摇摆棋盘,但我在使用HashMap将图标放到JButtons上时遇到了麻烦。 以下是我正在使用的类:

主类

public class GameGUI  extends JFrame {
private JButton tiles[][] = new JButton[8][8];
private HashMap<PieceKey, ImageIcon> icons = new HashMap<>();
public GameGUI(){
//swing shenannigans
initImages();
Tile[][] fenTiles = game.getFen().getTiles();
for(int row = 0; row <= 7; row++){
for(int column = 0; column <= 7; column++){
Piece piece = fenTiles[row][column].getPiece();
if(piece != null) {
tiles[row][column].setIcon(icons.get(new PieceKey(piece.getType(), piece.getColor())));
}
}
}

}
public void initImages(){
icons.put(new PieceKey(PieceType.pawn, Team.white), new ImageIcon("pieces/wpawn.png"));
//.....
}
public static void main(String args[]){
GameGUI asd = new GameGUI();
}
}

件钥匙类

public class PieceKey {
PieceType type;  //enum
Team color;      //enum
public PieceKey(PieceType type, Team color) {
this.color = color;
this.type = type;
}

@Override
public boolean equals(Object o){
if(this == o)
return true;
if(!(o instanceof PieceType))
return false;
PieceKey key = (PieceKey) o;
return this.type == key.type && this.color == key.color;
}
@Override
public int hashCode(){
return type.toString().hashCode() * color.toString().length();
}
}

团队枚举

public enum Team {
white, black;
}

片类型枚举

public enum PieceType {
pawn, rook, knight, bishop, king, queen;
}

我的问题是,每当我打电话时

icons.get(new PieceKey(piece.getType(), piece.getColor()));

它返回 null,所以我无法将图标放在按钮上,如果我手动执行此操作,它可以正常工作,因此问题出在 HashMap 上。我试图覆盖 PieceKey 类中的等于和哈希码函数,但它似乎不起作用。

问题可能出在您的PieceKeyequals方法上。使用instanceofPieceType使用不正确:

@Override
public boolean equals(Object o){
if(this == o)
return true;
// Please, note this, it will always return false, and the `Map`
// `equals` method for `get` and `put` will not work
if(!(o instanceof PieceType))
return false;
PieceKey key = (PieceKey) o;
return this.type == key.type && this.color == key.color;
}

如果应该是:

@Override
public boolean equals(Object o){
if(this == o)
return true;
// Please, note this
if(!(o instanceof PieceKey))
return false;
PieceKey key = (PieceKey) o;
return this.type == key.type && this.color == key.color;
}

jccampanero 的答案似乎是正确的,关于您对覆盖Object :: equals的实现细节有问题。

记录

另一种解决方案是 甚至不需要编写自己的equalshashCode。如果PieceKey类主要用于透明且不可变的携带数据,请将该类定义为记录。

你的整个班级都简化为这个简单的短线。

public record PieceKey ( PieceType type , Team color ) {}

作为记录,编译器隐式创建构造函数、getter、equals&hashCodetoString

创建实例的方式与传统类相同。

new PieceKey( PieceType.pawn , Team.white )

额外提示:在 Java 16 及更高版本中,作为创建记录功能的工作的一部分,我们现在可以在本地声明记录、枚举和接口。

您应该使用 IDE 来生成哈希代码并等于实现。

您应该拥有的最默认实现应该是这样的:

@Override
public int hashCode() {
return Objects.hash(type, color); // java.util.Objects
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof PieceKey) return false;
PieceKey other = (PieceKey) o;
return Objects.equals(type, other.type)
&& Objects.equals(color, other.color);
}

请注意,Java 17 记录根本不需要这个:

public record PriceKey(PieceType type, Team color) {}
  • hashCode()equals()是使用类型/颜色生成的。
  • 默认情况下,typecolorfinal的。

最新更新