Как определяется «сходство» для объектов Java? - PullRequest
4 голосов
/ 07 марта 2011

Я хочу добавить объекты пользовательского типа в набор. У меня есть несколько одинаковых, то есть они имеют одинаковые значения для своих открытых переменных.

Я не хочу, чтобы в набор было добавлено более одного экземпляра "одного и того же" объекта, но каждый раз, когда создается новый объект, он всегда добавляется.

Это потому, что метод equals для класса Object реализует максимально различающее возможное отношение эквивалентности для объектов: «Для любых ненулевых ссылочных значений x и y этот метод возвращает true, если и только если x и y ссылаются на один и тот же объект (x == y имеет значение true). "

Могу ли я переопределить метод equals для этого объекта, чтобы определить его по-другому?

Спасибо всем, проблема решена

Одинаковость для объектов Java определяется путем переопределения метода equals () объекта Java.

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((uri == null) ? 0 : uri.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Resource))
        return false;
    Resource other = (Resource) obj;
    if (uri == null) {
        if (other.uri != null)
            return false;
    } else if (!uri.equals(other.uri))
        return false;
    return true;
}

Ответы [ 8 ]

5 голосов
/ 07 марта 2011

Вам необходимо переопределить методы equals() и hashCode(), чтобы сообщить HashSet, что вы считаете равным.

Если вы используете TreeSet, вы должны реализовать Comparable вместо.

2 голосов
/ 07 марта 2011

Вы должны переопределить методы equals и hashCode для своего пользовательского типа.

Будьте осторожны, вы можете попасть во все виды дерьма здесь: например, если у вас есть подтипы для вашего пользовательского типа, вы можете столкнуться с другими проблемами равенства:

class Point {
    final int x;
    final int y;

    public Point(int x, int y) {
        this.x= x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) return true;   //If objects equal, is OK
        if (o instanceof Point) {
           Point that = (Point)o;
           return (x == that.x)  && y == that.y);
        }
        return false;
    }
}

class ColoredPoint extends Point {
   final Color color;
   ColoredPoint(int x, int y, Color color) {
      super(x, y);
      this.color = color
   }
}

Point p1 = new Point(1, 2);
ColoredPoint cp1 = new ColoredPoint(1, 2, Color.BLUE);
ColoredPoint cp1 = new ColoredPoint(1, 2, Color.RED);

В нынешнем виде p1, cp1 и cp2 все равны. Однако очевидно, что cp1 и cp2 не равны. Вам также нужно будет реализовать равенство в ColoredPoint для сравнения объектов ColoredPoint (но это нарушает равенство между p1 и cp1 или cp2).

Также убедитесь, что у ваших равных есть подпись выше. Распространенной ошибкой является определение его как public equals(Point that)..., что неверно.

См. http://www.artima.com/lejava/articles/equality.html для полного объяснения правил для equals и hashCode

2 голосов
/ 07 марта 2011

Как сказал SLaks, вы должны переопределить методы equals() и hashCode(). При переопределении equals() вы будете учитывать значения, например:

public class MyObject
  public int x;
  public int y;

  public boolean equals(Object obj) {
    return (obj instance of MyObject) && (obj.x==x && obj.y==y);
  }

  public int hashCode() { 
   return (x+y)*31;
  }

}

1 голос
/ 07 марта 2011

Относительно:

У меня такое ощущение, что моя проблема в том, что они не равны, поскольку это разные объекты, которые имеют одинаковые значения.

Реализация по умолчанию equals выполняет самую строгую - в документации сказано наиболее различающуюся - возможную форму проверки на равенство, которая заключается в проверке на идентичность (то есть две ссылкив одно и то же место в памяти).

Это одна из форм равенства, но не всегда самая полезная.Обычно вы хотите проверить, что два объекта имеют одинаковые свойства .Это совершенно естественная вещь, которую хочется делать, и она ни на что не годится.

1 голос
/ 07 марта 2011

Вы можете абсолютно переопределить equals () для сравнения значимых полей в вашем классе. Однако есть несколько важных вещей, о которых нужно помнить. От http://www.javapractices.com/topic/TopicAction.do?Id=17:

- если вы переопределяете равно, вы должны переопределить hashCode.

-hashCode должен генерировать равные значения для равных объектов.

-equals и hashCode должны зависеть от одного и того же набора "значимых" полей. Вы должны использовать один и тот же набор полей в обоих этих методах. Вы не обязаны использовать все поля. Например, вычисляемое поле, которое зависит от других, должно быть исключено из equals и hashCode.

Это в основном потому, что структура данных Set реализована в виде хэш-набора; он требует hashCode (), чтобы поместить объект в базовый массив и найти его позже, и ему требуется метод equals () для разрешения коллизий хеша (то есть нескольких объектов, которые хешируют одно и то же значение).

Вот хорошее руководство по реализации hashCode (): http://www.javamex.com/tutorials/collections/hash_function_guidelines.shtml

[EDIT]

Я бы хотел последовать совету Кости прочитать главу Джоша Блоха на эту тему. Это феноменальная книга.

1 голос
/ 07 марта 2011

Вы определенно должны переопределить equals и hashCode, так как они являются методами, используемыми Java для определения равенства объектов. По умолчанию все Objects различны.

За подробностями реализации обращайтесь к этой главе великой книги "Эффективная Java" Джошуа Блоха.

0 голосов
/ 07 марта 2011

Как уже указывалось SLaks, переопределение методов equals() и hashcode() определенно имеет смысл.Чтобы убедиться, что метод equals() ведет себя так, как вы хотите - в методе проверьте, содержат ли переменные-члены, которые вы рассматриваете как различающие два объекта, одинаковый набор значений или нет.

0 голосов
/ 07 марта 2011

Добавляет функциональность Set, проверяет метод hashcode (), и если он возвращает true, то он вызывает равный (). Каждый объект имеет различное расположение в памяти и метод equals () класса Object просто сравнивает биты расположения в памяти, чтобы проверить равенство. Следовательно, каждый объект добавляется.

Чтобы это работало, вам нужно добавить в ваш класс как метод hashCode (), так и метод equals (), и они будут сравнивать специфичные для класса атрибуты, которые, по вашему мнению, создают значение одинаковости.

...