HashMap get 返回 null,即使其中有键

HashMap get comes back with null even tho key is in it

我正在尝试创建一个带有图标的摇摆棋盘,但我无法使用 HashMap 将图标放到 JButton 上。 以下是我正在使用的 classes:

主要Class

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();
    }
}

PieceKeyclass

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;
}

PieceType 枚举

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

我的问题是每当我打电话给

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

它 return 为 null,所以我不能将图标放在按钮上,如果我手动操作它会很好,所以问题出在 HashMap 上。我试图覆盖 PieceKey class 中的 equals 和 hashcode 函数,但它似乎不起作用。

问题可能出在您的 PieceKey equals 方法中。您在使用 instanceof 时错误地使用了 PieceType:

@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;
}

关于您对 Object :: equals 的实现细节有疑问的 似乎是正确的。

记录

另一个解决方案是避免甚至需要编写您自己的 equalshashCode。如果您的 PieceKey class 主要用于透明且不可变的携带数据,请将 class 定义为 record.

你的整个 class 减少到这条简单的短线。

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

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

您可以使用与常规 class 相同的方式创建实例。

new PieceKey( PieceType.pawn , Team.white )

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

您应该使用 IDE 来生成您的 hashCode 和 equals 实现。

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

@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() 是使用 type/color 生成的。
  • typecolor默认为final