Почему ChronicleMap не использует hashCode или equals для ключей поиска?

import net.openhft.chronicle.map.ChronicleMap;

import java.io.File;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class App {

    public static void main(String[] args) throws Exception  {

        Map<Point, Point> map1 = new ConcurrentHashMap<>();

        ChronicleMap<Point, Point> map2 = ChronicleMap
                .of(Point.class, Point.class)
                .name("map")
                .averageKey(new Point(10, 10))
                .averageValue(new Point(10, 10))
                .entries(50)
                .createPersistedTo(new File("c:/temp/map/param.dat"));

        Point key = new Point(12, 12);
        key.hashCode();

        map1.put(key, key);
        map2.put(key, key);

        System.out.println("ConcurrentHashMap.get returned " + map1.get(new Point(12, 12)));
        System.out.println("ChronicleMap.get returned " + map2.get(new Point(12, 12)));
    }
}

class Point implements Serializable {
    private int x = 0;
    private int y = 0;
    private int _hash = 0;

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

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }


    @Override
    public String toString() {
        return super.toString() +  " {" + x + "," + y + "}";
    }

    @Override
    public int hashCode() {
        _hash = 1;
        _hash = _hash * 17 + x;
        _hash = _hash * 31 + y;
        return _hash;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof  Point) {
            return (x == ((Point) obj).getX()) && (y == ((Point) obj).getY());
        }
        return false;
    }
}

Как вы можете видеть в приведенном выше примере, поведение ChronicleMap немного отличается от ConcurrentHashMap (то же самое с HashMap), поскольку он не может искать ключи с помощью hashCode или равных.

может кто-нибудь точно определить, что можно сделать, чтобы исправить это?

ОБНОВИТЬ; При выполнении программа вернет следующие результаты:

ConcurrentHashMap.get returned App.Point@38f {12,12}
ChronicleMap.get returned null

person helloWorld998    schedule 29.12.2016    source источник
comment
Не связано. Почему _hash является полем (также известным как переменная экземпляра)? Это должна быть просто локальная переменная.   -  person Andreas    schedule 30.12.2016
comment
Как вы можете видеть в приведенном выше примере, поведение ChronicleMap немного отличается Я, должно быть, слепну, потому что я этого не вижу. Где в вопросе мы это увидим? Должны ли мы видеть это в выводе кода? Если это так, отредактируйте вопрос и покажите результат, иначе мы его не увидим.   -  person Andreas    schedule 30.12.2016
comment
Я обновил пример с результатом выполнения. в   -  person helloWorld998    schedule 30.12.2016


Ответы (1)


ChronicleMap сериализует ключ и берет 64-битный хэш байтов.

Используется 64-битный хэш, поскольку карта предназначена для очень большого количества ключей, например. миллиардов, в то время как 32-битный хеш, как правило, имеет высокую частоту коллизий, когда у вас есть миллионы ключей.

Он также может использовать более продвинутые стратегии хеширования, такие как эти https://github.com/OpenHFT/Zero-Allocation-Hashing

Примечание. Использование Serializable — наименее эффективный способ сделать это, но, тем не менее, он подходит для этого примера.

person Peter Lawrey    schedule 29.12.2016
comment
И чтобы уточнить, проблема заключается в том, что _hash - это поле, которое изначально равно 0, поэтому оно равно 0 для вызовов get(), но ненулевое для вызовов put() (поскольку hashCode() было вызвано), и, следовательно, ключи не те. Решение. Удалите это поле, его там быть не должно, так как оно должно быть просто локальной переменной в методе hashCode(). - person Andreas; 30.12.2016
comment
@Andreas Если бы это было кешированное значение, его можно было бы сделать transient, хотя лучше всего было бы сделать его локальной переменной. - person Peter Lawrey; 30.12.2016
comment
Верно, но это решит только проблему сериализации, а не проблему параллелизма. Если бы не поле _hash, класс был бы хорошим неизменяемым объектом с хорошим поведением. Несмотря на то, что x и y не объявлены final, они фактически являются окончательными. - person Andreas; 30.12.2016
comment
@Andreas При правильном использовании (переходное поле, кэширующее хэш и вычисляемое при нуле), как в String.hashCode, тогда не будет проблем с параллелизмом (кроме совершенно безвредных гонок с несколькими потоками, вычисляющими одно и то же значение). - person maaartinus; 07.01.2018
comment
@maaartinus Конечно, если использовать правильно. Он определенно не используется здесь должным образом, даже если он был сделан transient, и мой комментарий относится к показанному коду, а не к какой-то совершенно другой реализации hashCode(). Все, что я сказал, это то, что простое добавление transient не исправит код. Поскольку вычисление хеш-функции здесь очень простое, кэширование значения хеш-функции не требуется, и я поддерживаю свой первоначальный комментарий: удалите поле _hash. - person Andreas; 07.01.2018
comment
@ Андреас, я вижу, я комментировал то, что, как я думал, пытался сделать ОП, а не то, что они сделали. Вы совершенно правы! - person maaartinus; 07.01.2018