Какое значение возвращает метод hashCode()
в java?
Я прочитал, что это ссылка на память объекта... Когда я печатаю хеш-значение для new Integer(1)
, оно равно 1; для String("a")
- 97.
Я запутался: это ASCII или какой тип значения?
Какое значение возвращает метод hashCode()
в java?
Я прочитал, что это ссылка на память объекта... Когда я печатаю хеш-значение для new Integer(1)
, оно равно 1; для String("a")
- 97.
Я запутался: это ASCII или какой тип значения?
Хэш-код представляет собой целочисленное значение, которое представляет состояние объекта, на котором он был вызван. Вот почему Integer
, который установлен в 1, вернет хэш-код "1", потому что хэш-код Integer's
и его значение - одно и то же. Символьный хэш-код равен коду ASCII-символа. Если вы пишете настраиваемый тип, вы отвечаете за создание хорошей реализации hashCode
, которая лучше всего будет представлять состояние текущего экземпляра.
Значение, возвращаемое hashCode()
, никоим образом не гарантируется как адрес памяти объекта. Я не уверен в реализации в классе Object
, но имейте в виду, что большинство классов переопределят hashCode()
так, что два экземпляра, которые семантически эквивалентны (но не являются одинаковыми экземплярами), будут иметь хэш с тем же значением. Это особенно важно, если классы могут использоваться в другой структуре данных, например Set, которая полагается на hashCode
, согласующейся с equals
.
Нет hashCode()
, который однозначно идентифицирует экземпляр объекта независимо от того, что. Если вам нужен хэш-код на основе базового указателя (например, в реализации Sun), используйте System.identityHashCode()
- это будет делегировать метод по умолчанию hashCode
независимо от того, было ли оно переопределено.
Тем не менее, даже System.identityHashCode()
может возвращать один и тот же хеш для нескольких объектов. См. Комментарии для объяснения, но вот примерная программа, которая непрерывно генерирует объекты, пока не найдет два с тем же System.identityHashCode()
. Когда я запускаю его, он быстро находит два System.identityHashCode()
, которые совпадают, в среднем после добавления к карте около 86 000 объектов с длинной оболочкой (и обертки Integer для ключа).
public static void main(String[] args) {
Map<Integer,Long> map = new HashMap<>();
Random generator = new Random();
Collection<Integer> counts = new LinkedList<>();
Long object = generator.nextLong();
// We use the identityHashCode as the key into the map
// This makes it easier to check if any other objects
// have the same key.
int hash = System.identityHashCode(object);
while (!map.containsKey(hash)) {
map.put(hash, object);
object = generator.nextLong();
hash = System.identityHashCode(object);
}
System.out.println("Identical maps for size: " + map.size());
System.out.println("First object value: " + object);
System.out.println("Second object value: " + map.get(hash));
System.out.println("First object identityHash: " + System.identityHashCode(object));
System.out.println("Second object identityHash: " + System.identityHashCode(map.get(hash)));
}
Пример вывода:
Identical maps for size: 105822
First object value: 7446391633043190962
Second object value: -8143651927768852586
First object identityHash: 2134400190
Second object identityHash: 2134400190
Если вы хотите знать, как они имплантированы, я предлагаю вам прочитать источник. Если вы используете IDE, вы можете просто + на интересующем вас методе и посмотреть, как реализуется метод. Если вы не можете этого сделать, вы можете использовать Google для источника.
Например, Integer.hashCode() реализуется как
public int hashCode() {
return value;
}
и String.hashCode()
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
Я читал, что это ссылка на память объекта.
Нет. Object.hashCode()
используется для возврата адреса памяти около 14 лет назад. Не с тех пор.
какой тип значения
Что это зависит полностью от того, о каком классе вы говорите, и вне зависимости от того, переопределил ли он `Object.hashCode().
Метод hashCode()
часто используется для идентификации объекта. Я думаю, что реализация Object
возвращает указатель (не настоящий указатель, а уникальный идентификатор или что-то в этом роде) объекта. Но большинство классов переопределяют метод. Как класс String
. Два объекта String имеют не тот же указатель, но они равны:
new String("a").hashCode() == new String("a").hashCode()
Я думаю, что наиболее распространенное использование для hashCode()
находится в Hashtable
, HashSet
и т.д.
Изменить: (из-за недавнего downvote и на основе статьи, которую я прочитал о параметрах JVM)
С параметром JVM -XX:hashCode
вы можете изменить способ вычисления хэш-кода (см. Issue 222 специалистов Java-специалистов, Новостная рассылка).
HashCode == 0: просто возвращает случайные числа без отношения к тому, где в памяти объект найден. Насколько я могу разобраться, глобальные чтение-запись семян не оптимальна для систем с большим количеством процессоры.
HashCode == 1: подсчитывает значения хеш-кода, не уверен, какое значение они начинаются, но это кажется довольно высоким.
HashCode == 2: всегда возвращает тот же самый хэш-код идентификатора 1. Это можно использовать для проверки кода, который зависит от идентичности объекта. причина, по которой JavaChampionTest вернул URL Kirk в приведенном выше примере что все объекты возвращали один и тот же хэш-код.
HashCode == 3: подсчитывает значения хэш-кода, начиная с нуля. Это не выглядит потокобезопасным, поэтому несколько потоков могут генерировать объекты с одинаковым хеш-кодом.
HashCode == 4: похоже, это связано с расположением памяти на котором был создан объект.
HashCode >= 5: Это алгоритм по умолчанию для Java 8 и имеет для каждой нити. В нем используется схема переноса x-shift Marsaglia для производства псевдослучайные числа.
Object.hashCode(), если память правильно работает (проверьте JavaDoc для java.lang.Object), зависит от реализации и будет меняться в зависимости от объекта (Sun JVM выводит значение из значения ссылки к объекту).
Обратите внимание, что если вы реализуете какой-либо нетривиальный объект и хотите правильно хранить его в HashMap или HashSet, вы ДОЛЖНЫ переопределить hashCode() и equals(). hashCode() может делать все, что вам нравится (это полностью легально, но субоптимально, чтобы оно возвращалось 1.), но очень важно, чтобы, если ваш метод equals() возвращает true, тогда значение, возвращаемое hashCode() для обоих объектов, равно.
Путаница и непонимание hashCode() и equals() - большой источник ошибок. Убедитесь, что вы хорошо знакомы с JavaDocs для Object.hashCode() и Object.equals(), и я гарантирую, что потраченное время будет платить за себя.
public static int murmur3_32(int paramInt1, char[] paramArrayOfChar, int paramInt2, int paramInt3) {
/* 121 */ int i = paramInt1;
/* */
/* 123 */ int j = paramInt2;
/* 124 */ int k = paramInt3;
/* */
/* */ int m;
/* 127 */ while (k >= 2) {
/* 128 */ m = paramArrayOfChar[(j++)] & 0xFFFF | paramArrayOfChar[(j++)] << '\020';
/* */
/* 130 */ k -= 2;
/* */
/* 132 */ m *= -862048943;
/* 133 */ m = Integer.rotateLeft(m, 15);
/* 134 */ m *= 461845907;
/* */
/* 136 */ i ^= m;
/* 137 */ i = Integer.rotateLeft(i, 13);
/* 138 */ i = i * 5 + -430675100;
/* */ }
/* */
/* */
/* */
/* 143 */ if (k > 0) {
/* 144 */ m = paramArrayOfChar[j];
/* */
/* 146 */ m *= -862048943;
/* 147 */ m = Integer.rotateLeft(m, 15);
/* 148 */ m *= 461845907;
/* 149 */ i ^= m;
/* */ }
/* */
/* */
/* */
/* 154 */ i ^= paramInt3 * 2;
/* */
/* */
/* 157 */ i ^= i >>> 16;
/* 158 */ i *= -2048144789;
/* 159 */ i ^= i >>> 13;
/* 160 */ i *= -1028477387;
/* 161 */ i ^= i >>> 16;
/* */
/* 163 */ return i;
/* */ }
Если вам действительно интересно узнать, прочитайте этот код в Hashing.class;
Здесь первый параметр HASHING_SEED вычисляется на основе кода ниже
{
long nanos = System.nanoTime();
long now = System.currentTimeMillis();
int SEED_MATERIAL[] = {
System.identityHashCode(String.class),
System.identityHashCode(System.class),
(int) (nanos >>> 32),
(int) nanos,
(int) (now >>> 32),
(int) now,
(int) (System.nanoTime() >>> 2)
};
// Use murmur3 to scramble the seeding material.
// Inline implementation to avoid loading classes
int h1 = 0;
// body
for (int k1 : SEED_MATERIAL) {
k1 *= 0xcc9e2d51;
k1 = (k1 << 15) | (k1 >>> 17);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
h1 = h1 * 5 + 0xe6546b64;
}
// tail (always empty, as body is always 32-bit chunks)
// finalization
h1 ^= SEED_MATERIAL.length * 4;
// finalization mix force all bits of a hash block to avalanche
h1 ^= h1 >>> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >>> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >>> 16;
HASHING_SEED = h1;
}
второй параметр - это массив char String, третий всегда '0', а четвертый - длина массива char.
И приведенный выше расчет предназначен только для хеш-кода String.
Для всех целых чисел его хеш-код будет его целочисленным значением. Для char (до двух букв) это будет ASCII-код.