【问题标题】:Equals method is not working for two same objectEquals 方法不适用于两个相同的对象
【发布时间】:2021-03-05 06:23:11
【问题描述】:

我编写了一个代码来查找唯一的图像。如果两个图像具有相同的名称(即使扩展名不同)并且大小相等(宽度 * 长度),则它们是相等的。 但它未能找到独特的图像。 即使重写了 equals 方法,HashSet 方法也无法识别两个相似的对象。

    import java.util.*;

    class UniqueImages {
    public static class Image {
    private String filename;
    private int width;
    private int height;
    public Image(String filename, int width, int height) {
        this.filename = filename;
        this.width = width;
        this.height = height;
    }
    
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((filename == null) ? 0 : filename.hashCode());
        result = prime * result + height;
        result = prime * result + width;
        return result;
    }

    /**
     * Two Images are considered equal if they have
     * the same filename (without the extension), and the
     * same number of pixels.
     * Thus, flag.jpg with width=60 height=40 is
     * equal to flag.gif with width=40 and height=60
     */
    public boolean equals(Object other) {
        Image o = (Image)other;
        if (filename == null || o.filename == null)
            return false;
        String[] components = filename.split("\\.");
        String[] ocomponents = o.filename.split("\\.");
        return components[0].equals(ocomponents[0]) && 
            width * height == o.width * o.height;
      }

        public String toString() {
           return "Image: filename=" + filename + " Size=" + width*height;
      }
    }

    public static void printImages(Set<Image> images) {
        for(Image image: images) {
           System.out.println(image);
      }
    }

    public static void main(String[] args) {
    Image[] images = {new Image("flag.jpg", 40, 60),
                      new Image("flag.gif", 40, 60),
                      new Image("smile.gif", 100, 200),
                      new Image("smile.gif", 50, 400),
                      new Image("other.jpg", 40, 60),
                      new Image("lenna.jpg", 512, 512),
                      new Image("Lenna.jpg", 512, 512)};
    
          Set<Image> set = new HashSet<Image>(Arrays.asList(images));
          UniqueImages.printImages(set);
        }
      }

【问题讨论】:

  • 您可能希望名称比较不区分大小写。此外,是否应该将 50x400 图像视为与 100x200 图像相同?对我来说没有意义。
  • 两者的总大小是一样的,所以我认为它是一样的。
  • 你的 hashCode() 和 equals() 不一致。您应该使 hashCode 遵循与 equals 相同的规则,这意味着忽略文件扩展名。
  • 你可以让你的IDE为你生成equalshashCode

标签: java collections set equals hashset


【解决方案1】:

Eran 已经给出了答案。但是,我想强调您的.equals() 实施中的问题。你的演员表不安全。以下是我的编写方式(使用 Bloch 的 Effective Java 中给出的模板):

public boolean equals(Object o) {
    if(o == this) {
        return true;
    }
    if(!(o instance of Image)) {
        return false;
    }
    Image o = (Image)other;
    if (filename == null || o.filename == null)
        return false;
    String[] components = filename.split("\\.");
    String[] ocomponents = o.filename.split("\\.");
    return components[0].equals(ocomponents[0]) && 
        width * height == o.width * o.height;
}

【讨论】:

    【解决方案2】:

    如果您的equals() 方法认为两个具有相同总大小的图像相等(即使它们没有相同的widthheight),它们也应该具有相同的hashCode()

    但这不是唯一的问题。您还应该更改hashCode() 以忽略文件名后缀,以使其适合equals() 的实现。

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((filename == null) ? 0 : filename.split("\\.")[0].hashCode());
        result = prime * result + (height * width);
        return result;
    }
    

    通过这两个更改,HashSet 将消除两个重复项,从而导致:

    Image: filename=smile.gif Size=20000
    Image: filename=flag.jpg Size=2400
    Image: filename=lenna.jpg Size=262144
    Image: filename=other.jpg Size=2400
    Image: filename=Lenna.jpg Size=262144
    

    【讨论】:

    • 可能值得选择一个子字符串before文件名的最后一个点,而不是前缀before第一个点。
    • @AlexRudenko 可能。重要的是hashCode() 实现符合equals() 实现,这就是我所做的。
    • 同意,这是一个考虑图像文件 equal 的奇特案例 :)
    猜你喜欢
    • 2013-10-27
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 2014-08-11
    • 1970-01-01
    相关资源
    最近更新 更多