Я написал код для поиска уникальных изображений. Два изображения равны, если у них одинаковое имя (даже если расширение разное) и одинаковый размер (ширина * длина). Но не удается найти уникальные изображения. Даже после переопределения метода 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);
        }
      }
4
vikash srivastava 22 Ноя 2020 в 13:39

2 ответа

Лучший ответ

Если ваш метод equals() считает два изображения с одинаковым общим размером равными (даже если у них разные width и height), они также должны иметь одинаковые 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
3
Eran 22 Ноя 2020 в 10:53

Эран уже дал ответ. Однако я хотел бы выделить проблемы в вашей реализации .equals(). Ваш гипс небезопасен. Вот как я бы это написал (используя шаблон, приведенный в 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;
}
0
Prashant Pandey 22 Ноя 2020 в 12:01
64953134