Может ли Java hashCode выдавать одинаковое значение для разных строк?

Возможно ли иметь один и тот же хэш-код для разных строк с использованием java-функции hashcode? или если это возможно, то какой% его возможности?

Ответ 1

Явный хэш-код Java - 32 бит. Количество возможных цепочек хэшей бесконечно.

Итак, да, будут столкновения. Процент бессмыслен - существует бесконечное количество элементов (строк) и конечное число возможных хэшей.

Ответ 2

ДА. Много.

Посмотрите на следующую пару

  • "FB" и "Ea"

может возвращать один и тот же хэш-код, даже если символы в нем не совпадают.

В основном это сумма символов в строке, умноженная на целое число.

Ответ 3

Да, это вполне возможно. Вероятность строки (или какого-либо другого типа объекта - просто предполагая, что вы будете использовать строки в этом примере), имеющие тот же хэш-код, что и некоторая другая строка в коллекции, зависит от размера этой коллекции (если предположить, что все строки в эта коллекция уникальна). Вероятности распределяются следующим образом:

  • С набором размеров ~ 9 000 у вас будет 1% -ный шанс, что две строки столкнутся с хешем в наборе
  • При наборе размера ~ 30 000 у вас будет 10% вероятность того, что две строки столкнутся с хешем в наборе
  • С набором размеров ~ 77 000 у вас будет 50% вероятность того, что две строки столкнутся с хешем в наборе

Сделанные предположения:

  • Функция hashCode не имеет смещения
  • Каждая строка в вышеупомянутом наборе уникальна

Этот сайт четко объясняет: http://eclipsesource.com/blogs/2012/09/04/the-3-things-you-should-know-about-hashcode/ (Посмотрите на "второе, что вы должны знать" )

Ответ 4

если это возможно, то каков% его возможности?

Это не особо важный вопрос.

Однако, если в функции hashcode нет системного смещения, вероятность того, что любые две разные (не равные) строки имеют один и тот же хэш-код, будет равна 1 в 2 ^ 32.

Это предполагает, что строки выбираются случайным образом из множества всех возможных значений String. Если вы ограничите набор различными способами, вероятность будет отличаться от указанного выше числа. (Например, существование столкновения "FB" / "Ea" означает, что вероятность столкновения в множестве всех двух буквенных строк выше нормы.)


Еще одна вещь, которую следует отметить, состоит в том, что вероятность 2 ^ 32 различных строк, выбранных случайным образом (из гораздо большего несмещенного набора строк), не имеющих хэш-коллизий, исчезающе мала. Чтобы понять, почему, прочитайте страницу Википедии на Парад дня рождения. На самом деле, единственный способ, которым вы не получите никаких хэш-коллизий в наборе из 2 ^ 32 разных строк, - это выбрать или сгенерировать строки. (И даже формирование набора путем выбора случайно сгенерированных строк будет стоить дорогостоящим.)

Ответ 5

Это не будет напрямую отвечать на ваш вопрос, но я надеюсь, что это поможет.

Ниже приведен исходный код java.lang.String.

/**
 * Returns a hash code for this string. The hash code for a
 * <code>String</code> object is computed as
 * <blockquote><pre>
 * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 * </pre></blockquote>
 * using <code>int</code> arithmetic, where <code>s[i]</code> is the
 * <i>i</i>th character of the string, <code>n</code> is the length of
 * the string, and <code>^</code> indicates exponentiation.
 * (The hash value of the empty string is zero.)
 *
 * @return  a hash code value for this object.
 */
public int hashCode() {
    int h = hash;
    int len = count;
    if (h == 0 && len > 0) {
    int off = offset;
    char val[] = value;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
}

Ответ 6

Да, две строки могут иметь один и тот же хэш-код. Если вы посмотрите на статью Wikipedia, вы увидите, что оба "FB" и "Ea" имеют одинаковый хэш-код. В контракте метода ничего нет, говоря, что hashCode() следует использовать для сравнения для равенства, вы хотите использовать equals() для этого.

Так как Java 1.2, String реализует hashCode() с использованием алгоритма суммирования продукта по всему тексту строки.

Ответ 7

Да, по определению концепции голубя-дыры, две разные строки могут создавать один и тот же хэш-код, и код всегда должен записываться для удовлетворения таких условий (как правило, не прерывая).

Ответ 8

Процент коллизий для случайных строк должен быть минимальным. Однако, если вы используете хэш-строки из внешних источников, злоумышленник может легко создать сотни тысяч строк, имеющих один и тот же хэш-код. В java HashMap все они будут сопоставлены с одним ведром и эффективно превратят карту в связанный список. Тогда время доступа к карте будет пропорционально размеру карты вместо константы, что приведет к атаке отказа в обслуживании.

См. эту страницу в Эффективные атаки DoS против Plattforms для веб-приложений для получения дополнительной информации о ссылках на презентацию.

Ответ 9

Да, это возможно, потому что один из контрактов между методом equals() и hashCode() класса Object равен.......... Если два объекта не равны в соответствии с методом equals(), то гарантии нет что их hashCode будет таким же, hashCode может/не может быть равным. то есть, если obj1.equals(obj2) возвращает false, то obj1.hashCode() == obj2.hashCode() может/не может возвращать true. Пример:

    String str1 = "FB";
    String str2 = "Ea";
    System.out.println(str1.equals(str2));// false
    System.out.println(str1.hashCode() == str2.hashCode()); // true

Ответ 10

//Вы можете запустить приведенный ниже код с помощью -Xmx2100m и получить несколько результатов, достаточных для заполнения консоли

'

import java.util.HashMap;

public class TestHashCollision {
        public static void main(String[] args) {
        final String TEXT = "was stored earlier had the same hash as";
        HashMap<Integer,String> hs=new HashMap<>();
        long t1=System.currentTimeMillis();
        long t2=System.currentTimeMillis();
        for(long l=0;l<Long.MAX_VALUE;l++) {
            String key="d"+l;
            if(hs.containsKey(key.hashCode())) {
                System.out.println("'"+hs.get(key.hashCode())+"' "+TEXT+" '"+key+"'");//System.exit(0);
            } else {
                hs.put(key.hashCode(),key);
            }
            t2=System.currentTimeMillis();
            if(t2-t1>10000) {
                t1=System.currentTimeMillis();
                System.out.println("10 seconds gone! size is:"+hs.size());
            }
        }
        System.out.println("Done"); 
    }
}

'