Как предотвратить HashMap для хранения дублированного значения типа объекта и возвращает существующую ссылку на значение? [Дубликат]

NOLOCK эквивалентно READ UNCOMMITTED, однако Microsoft заявляет, что вы не должны использовать его для операторов UPDATE или DELETE:

Для операторов UPDATE или DELETE: эта функция будет быть удалены в будущей версии Microsoft SQL Server. Избегайте использования этой функции в новых разработках и планируйте изменять приложения, которые в настоящее время используют эту функцию.

blockquote>

http://msdn.microsoft.com/en-us/library/ ms187373.aspx

Эта статья относится к SQL Server 2005, поэтому поддержка NOLOCK существует, если вы используете эту версию. В целях обеспечения будущего кода (при условии, что вы решили использовать грязные чтения) вы можете использовать это в своих хранимых процедурах:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

617
задан George Stocker 11 August 2014 в 20:02
поделиться

11 ответов

Теория (для юристов языка и математически склонная):

equals() ( javadoc ) должна определять отношение эквивалентности (оно должно быть рефлексивным , симметричные и транзитивные ). Кроме того, он должен быть согласованным (если объекты не изменены, то он должен продолжать возвращать одно и то же значение). Кроме того, o.equals(null) всегда должен возвращать false.

hashCode() ( javadoc ) также должен быть согласован (если объект не изменяется в терминах equals(), он должен продолжать возвращать одно и то же значение).

Связь между двумя методами:

Всякий раз, когда a.equals(b), тогда a.hashCode() должен быть таким же, как b.hashCode().

На практике:

Если вы переопределите один, тогда вы должны переопределить другой.

Используйте тот же набор полей, который вы используете для вычисления equals(), чтобы вычислить hashCode().

Используйте отличные вспомогательные классы EqualsBuilder и HashCodeBuilder из библиотеки Apache Commons Lang . Пример:

public class Person {
    private String name;
    private int age;
    // ...

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
            // if deriving: appendSuper(super.hashCode()).
            append(name).
            append(age).
            toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
       if (!(obj instanceof Person))
            return false;
        if (obj == this)
            return true;

        Person rhs = (Person) obj;
        return new EqualsBuilder().
            // if deriving: appendSuper(super.equals(obj)).
            append(name, rhs.name).
            append(age, rhs.age).
            isEquals();
    }
}

Также помните:

При использовании хэш-набора Collection или Map , таких как HashSet , LinkedHashSet , HashMap , Hashtable или WeakHashMap , убедитесь, что hashCode ( ) ключевых объектов, которые вы помещаете в коллекцию, никогда не изменяется, пока объект находится в коллекции. Пуленепробиваемый способ гарантировать, что ваши ключи неизменяемы, , который имеет и другие преимущества .

1376
ответ дан 18 revs, 10 users 77% 1 September 2018 в 05:21
поделиться

Все еще удивляюсь, что никто не рекомендовал библиотеку guava для этого.

 //Sample taken from a current working project of mine just to illustrate the idea

    @Override
    public int hashCode(){
        return Objects.hashCode(this.getDate(), this.datePattern);
    }

    @Override
    public boolean equals(Object obj){
        if ( ! obj instanceof DateAndPattern ) {
            return false;
        }
        return Objects.equal(((DateAndPattern)obj).getDate(), this.getDate())
                && Objects.equal(((DateAndPattern)obj).getDate(), this.getDatePattern());
    }
31
ответ дан Andy Thomas 1 September 2018 в 05:21
поделиться

Осветление о obj.getClass() != getClass().

Это утверждение является результатом нечеткого наследования equals(). Спецификация JLS (спецификация языка Java) указывает, что если A.equals(B) == true, то B.equals(A) также должен возвращать true. Если вы опускаете этот оператор, наследующий классы, которые переопределяют equals() (и меняют его поведение), это приведет к нарушению этой спецификации.

Рассмотрим следующий пример того, что происходит, когда оператор опущен:

    class A {
      int field1;

      A(int field1) {
        this.field1 = field1;
      }

      public boolean equals(Object other) {
        return (other != null && other instanceof A && ((A) other).field1 == field1);
      }
    }

    class B extends A {
        int field2;

        B(int field1, int field2) {
            super(field1);
            this.field2 = field2;
        }

        public boolean equals(Object other) {
            return (other != null && other instanceof B && ((B)other).field2 == field2 && super.equals(other));
        }
    }    

Выполнение new A(1).equals(new A(1)) Кроме того, результат new B(1,1).equals(new B(1,1)) выдаёт true, как и должно быть.

Это выглядит очень хорошо, но посмотрите, что произойдет, если мы попытаемся использовать оба класса:

A a = new A(1);
B b = new B(1,1);
a.equals(b) == true;
b.equals(a) == false;

Очевидно, что это неправильно.

Если вы хотите обеспечить симметричное условие. a = b, если b = a и принцип подстановки Лискова super.equals(other) не только в случае экземпляра B, но и проверьте для экземпляра A:

if (other instanceof B )
   return (other != null && ((B)other).field2 == field2 && super.equals(other)); 
if (other instanceof A) return super.equals(other); 
   else return false;

Который выведет:

a.equals(b) == true;
b.equals(a) == true;

Если, если a не является ссылкой B, то это может быть ссылка класса A (поскольку вы его расширяете), в этом случае вы вызываете super.equals() тоже.

80
ответ дан BartoszKP 1 September 2018 в 05:21
поделиться

Один найденный мной вопрос: где два объекта содержат ссылки друг на друга (один пример - отношения родителя / ребенка с методом удобства родителя, чтобы получить всех детей). Такие типы довольно распространены, например, при сопоставлении Hibernate.

Если вы включаете оба конца отношений в свои тесты hashCode или equals, можно попасть в рекурсивный цикл, который заканчивается исключением StackOverflowException. Самое простое решение - не включать коллекцию getChildren в методы.

6
ответ дан Darren Greaves 1 September 2018 в 05:21
поделиться

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

  1. Используйте оператор instanceof.
  2. Используйте this.getClass().equals(that.getClass()).

Я использую # 1 в реализации final equals или при реализации интерфейса, который предписывает алгоритм для equals (например, java.util интерфейсы коллекции - правильный путь для проверки с помощью (obj instanceof Set) или любого другого интерфейса, который вы реализуете). Обычно это плохой выбор, когда equals можно переопределить, потому что это нарушает свойство симметрии.

Вариант № 2 позволяет безопасно расширять класс без превышения равных или нарушения симметрии.

Если ваш class также Comparable, методы equals и compareTo также должны быть последовательными. Вот шаблон для метода equals в классе Comparable:

final class MyClass implements Comparable<MyClass>
{

  …

  @Override
  public boolean equals(Object obj)
  {
    /* If compareTo and equals aren't final, we should check with getClass instead. */
    if (!(obj instanceof MyClass)) 
      return false;
    return compareTo((MyClass) obj) == 0;
  }

}
18
ответ дан erickson 1 September 2018 в 05:21
поделиться

Логически мы имеем:

a.getClass().equals(b.getClass()) && a.equals(b)a.hashCode() == b.hashCode()

Но не наоборот!

7
ответ дан Hermes 1 September 2018 в 05:21
поделиться

Для равных взгляните на Секреты равных на Angelika Langer . Я люблю это очень сильно. Она также очень часто задает вопрос о дженериках в Java . Просмотрите другие статьи здесь (прокрутите вниз до «Core Java»), где она также продолжит работу с Part-2 и «сравнение смешанного типа». Получайте удовольствие, читая их!

15
ответ дан Johannes Schaub - litb 1 September 2018 в 05:21
поделиться

В суперклассе есть два метода: java.lang.Object. Мы должны переопределить их к пользовательскому объекту.

public boolean equals(Object obj)
public int hashCode()

Равные объекты должны создавать одинаковый хеш-код, если они равны, однако неравные объекты не должны создавать отдельные хэш-коды.

public class Test
{
    private int num;
    private String data;
    public boolean equals(Object obj)
    {
        if(this == obj)
            return true;
        if((obj == null) || (obj.getClass() != this.getClass()))
            return false;
        // object must be Test at this point
        Test test = (Test)obj;
        return num == test.num &&
        (data == test.data || (data != null && data.equals(test.data)));
    }

    public int hashCode()
    {
        int hash = 7;
        hash = 31 * hash + num;
        hash = 31 * hash + (null == data ? 0 : data.hashCode());
        return hash;
    }

    // other methods
}

Если вы хотите получить больше, пожалуйста, проверьте эту ссылку как http://www.javaranch.com/journal/2002/10/equalhash.html

Это другой пример, http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html

Удачи ! @. @

25
ответ дан Luna Kong 1 September 2018 в 05:21
поделиться

Есть некоторые проблемы, заслуживающие внимания, если вы имеете дело с классами, которые сохраняются с использованием Object-Relationship Mapper (ORM), такого как Hibernate, если вы не думаете, что это было необоснованно уже сложно!

Lazy загруженные объекты являются подклассами

Если ваши объекты сохраняются с использованием ORM, во многих случаях вы будете иметь дело с динамическими прокси, чтобы избежать слишком раннего извлечения объекта из хранилища данных. Эти прокси реализованы как подклассы вашего собственного класса. Это означает, что this.getClass() == o.getClass() вернет false. Например:

Person saved = new Person("John Doe");
Long key = dao.save(saved);
dao.flush();
Person retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass()); // Will return false if Person is loaded lazy

Если вы имеете дело с ORM, использование o instanceof Person - это единственное, что будет вести себя правильно.

Lazy загруженные объекты имеют нулевые поля

ORM обычно используют геттеры для принудительной загрузки ленивых загружаемых объектов. Это означает, что person.name будет null, если person ленив загружен, даже если person.getName() принудительно загружает и возвращает «John Doe». По моему опыту, это чаще встречается в hashCode() и equals().

Если вы имеете дело с ORM, обязательно используйте геттеры и никогда не ссылайтесь на ссылки в hashCode() и equals().

Сохранение объекта изменит его состояние

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

Я часто использую шаблон

if (this.getId() == null) {
    return this == other;
}
else {
    return this.getId().equals(other.getId());
}

Но: вы не можете включить getId() в hashCode(). Если вы это сделаете, когда объект сохраняется, изменяется его hashCode. Если объект находится в HashSet, вы «никогда» не найдете его снова.

В моем примере Person я, вероятно, использовал бы getName() для hashCode и getId() plus getName() (только для паранойи) для equals(). Это нормально, если есть риск «столкновения» для hashCode(), но никогда не подходит для equals().

hashCode() должен использовать неизменяемый поднабор свойств из equals()

281
ответ дан maaartinus 1 September 2018 в 05:21
поделиться

Для реализации, основанной на наследовании, проверьте решение Tal Cohen, Как правильно выполнить метод equals ()?

Резюме:

В своей книге «Эффективное руководство по языку программирования Java» (Addison-Wesley, 2001) Джошуа Блох утверждает, что «просто невозможно расширить экземпляр класса и добавить аспект при сохранении равного контракта». Таль не согласен.

Его решение состоит в том, чтобы реализовать equals (), вызвав другой несимметричный blindlyEquals () в обоих направлениях. blindlyEquals () переопределяется подклассами, equals () наследуется и никогда не переопределяется.

Пример:

class Point {
    private int x;
    private int y;
    protected boolean blindlyEquals(Object o) {
        if (!(o instanceof Point))
            return false;
        Point p = (Point)o;
        return (p.x == this.x && p.y == this.y);
    }
    public boolean equals(Object o) {
        return (this.blindlyEquals(o) && o.blindlyEquals(this));
    }
}

class ColorPoint extends Point {
    private Color c;
    protected boolean blindlyEquals(Object o) {
        if (!(o instanceof ColorPoint))
            return false;
        ColorPoint cp = (ColorPoint)o;
        return (super.blindlyEquals(cp) && 
        cp.color == this.color);
    }
}

Обратите внимание, что equals () должно работать через иерархии наследования, если Лисков должен быть выполнен Замена .

41
ответ дан reevesy 1 September 2018 в 05:21
поделиться
Метод

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

как int значение 10 всегда равно 10. Но этот метод equals () равен равенству двух объектов. Когда мы говорим объект, у него будут свойства. Для решения вопроса о равенстве рассматриваются эти свойства. Нет необходимости, чтобы все свойства были приняты во внимание, чтобы определить равенство, и в отношении определения класса и контекста его можно решить. Тогда метод equals () может быть переопределен.

мы всегда должны переопределять метод hashCode () всякий раз, когда мы переопределяем метод equals (). Если нет, что произойдет? Если мы используем hashtables в нашем приложении, он не будет вести себя так, как ожидалось. Поскольку hashCode используется для определения сохраненного значения сохраненных значений, он не будет возвращать правильное соответствующее значение для ключа.

Реализованная реализация по умолчанию - метод hashCode () в классе Object использует внутренний адрес объекта и преобразует его в целое число и возвращает его.

public class Tiger {
  private String color;
  private String stripePattern;
  private int height;

  @Override
  public boolean equals(Object object) {
    boolean result = false;
    if (object == null || object.getClass() != getClass()) {
      result = false;
    } else {
      Tiger tiger = (Tiger) object;
      if (this.color == tiger.getColor()
          && this.stripePattern == tiger.getStripePattern()) {
        result = true;
      }
    }
    return result;
  }

  // just omitted null checks
  @Override
  public int hashCode() {
    int hash = 3;
    hash = 7 * hash + this.color.hashCode();
    hash = 7 * hash + this.stripePattern.hashCode();
    return hash;
  }

  public static void main(String args[]) {
    Tiger bengalTiger1 = new Tiger("Yellow", "Dense", 3);
    Tiger bengalTiger2 = new Tiger("Yellow", "Dense", 2);
    Tiger siberianTiger = new Tiger("White", "Sparse", 4);
    System.out.println("bengalTiger1 and bengalTiger2: "
        + bengalTiger1.equals(bengalTiger2));
    System.out.println("bengalTiger1 and siberianTiger: "
        + bengalTiger1.equals(siberianTiger));

    System.out.println("bengalTiger1 hashCode: " + bengalTiger1.hashCode());
    System.out.println("bengalTiger2 hashCode: " + bengalTiger2.hashCode());
    System.out.println("siberianTiger hashCode: "
        + siberianTiger.hashCode());
  }

  public String getColor() {
    return color;
  }

  public String getStripePattern() {
    return stripePattern;
  }

  public Tiger(String color, String stripePattern, int height) {
    this.color = color;
    this.stripePattern = stripePattern;
    this.height = height;

  }
}

Пример вывода кода:

bengalTiger1 and bengalTiger2: true 
bengalTiger1 and siberianTiger: false 
bengalTiger1 hashCode: 1398212510 
bengalTiger2 hashCode: 1398212510 
siberianTiger hashCode: –1227465966
11
ответ дан user1431282 1 September 2018 в 05:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: