Используя char [] массив в HashMap в Java - PullRequest
2 голосов
/ 11 августа 2011

Я использую HashMap с массивом символов в качестве ключа. Но когда я помещаю ключ, значение в HashMap и печатаю его, значение, напечатанное как ключ, является каким-то странным значением. Если вместо этого я использую строку, она работает нормально. Пожалуйста, дайте мне знать, как заставить это работать для значений char [].

            while((ch = br.read()) != -1) {
            s = new char[10];
            s[i++] = (char)ch;

            while( (i < 10) && ((ch = br.read()) != -1)) {
                s[i++] = (char)ch;                  
            }

            //System.out.println(s);
            hmap.put(s, 1); 
            //System.out.println(hmap);
            i = 0;              
        }

Ключ: BZOUA1578L Значение: 1

Содержимое в хэш-карте {{C @ 31ff23 = 1} вместо {BZOUA1578L, 1}

Ответы [ 6 ]

4 голосов
/ 11 августа 2011

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

Тогда вам придется думать о другом.

  • Вы можете использовать TreeMap<char[], V> с пользовательским Comparator ... но это мера с ограничением.

  • Вы могли бы реализовать пользовательский класс Map на основе хеш-таблицы, который использовал бы char[] в качестве ключа, но выполнял тесты хэширования и равенства массива без использования ключевого объекта equals(Object)и hashcode() методы.Это также является мерой с ограничением зазора.

  • Вы можете получить машину большего размера ... еще одну меру с ограничением зазора.

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

То, что вы сейчас делаетене масштабируетсяДаже если вам удастся реализовать карту с помощью клавиш char[] вместо клавиш String, вы, вероятно, только уменьшите пространство, используемое для удержания клавиш, наполовину.Лучшее, что это даст вам, - это способность обрабатывать примерно вдвое больше ключей, чем вы в настоящее время можете обрабатывать.Затем вы снова попадаете в стену.

В долгосрочной перспективе последний вариант является наилучшим, если вы хотите продолжать увеличиваться.


Кстати, предложение @Sean Patrick Floyd о стажировкеключевые строки, вероятно, только усугубят ситуацию.Во-первых, вы никогда не получите строки, которые равны, но не == как ключи на одной карте.Так что интернирование ничего не спасает.Во-вторых, интернирование выполняется с использованием закрытой хеш-таблицы, и JVM необходимо выделить пространство для представления этой таблицы.

Единственный сценарий, в котором интернирование потенциально целесообразно, - это если строки, которые вы используете для выполнения поиска по картескорее всего переживет несколько циклов GC.Только тогда может сохранить пространство.


Наконец, есть один сценарий, который может привести к тому, что ваши ключевые строки будут использовать гораздо больше памяти, чем вы думаете.Примите во внимание следующее:

BufferedReader br = ...
Map<String, Value> map = new HashMap<String, Value>();

String line;
while ((line = br.readLine()) != null) {
    ...
    String key = line.substring(...);
    map.put(key, ...);
}

Проблема в том, что метод substring имеет ту же основу char[], что и исходная строка.Если key является долгоживущим (что, вероятно, будет), это означает, что исходный большой резервный массив также будет долгоживущим, даже если мы только когда-либо будем ссылаться на фрагмент этого массива через key object.

Решение состоит в том, чтобы написать это:

    String key = new String(line.substring(...));

, что вызывает копирование символов в новый (меньший) массив символов.

ОБНОВЛЕНИЕ - Изменения в реализации java.lang.String в Java 7 решают эту проблему.Методы substring теперь делают копию соответствующего среза резервного массива.

4 голосов
/ 11 августа 2011

Печать - это наименьшая из ваших проблем, правда.Реальная проблема заключается в том, что char [] не имеет осмысленной реализации методов equals() и hashCode(), на которые опирается HashMap.Поэтому карта не будет распознавать разные массивы с одинаковым содержимым и одинаковыми ключами, что, по всей вероятности, в первую очередь подрывает вашу цель использования хеш-карты.

Поэтому вам нужно обернуть массивы в нечтоимеет equals() и hashCode().Могу ли я предложить обернуть их в java.lang.String?

4 голосов
/ 11 августа 2011

Это потому, что у массивов нет метода toString ().То, что вы видите, является выводом Object.toString ():

return getClass().getName() + "@" + Integer.toHexString(hashCode());

В вашем случае:

[C     = internal name of char[].class
@      = "@"
31ff23 = your array's identity hash code as hey String
=1     = the value

Кстати, они также не имеют реализации hashCode (),поэтому они создают плохие ключи для HashMaps (см. этот похожий вопрос об использовании байтовых массивов в качестве ключей HashMap ).

3 голосов
/ 11 августа 2011
Метод

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

. Вы не должны использовать массивы в качестве ключей в HashMap, поскольку они не реализуют hashCode() и equals() на основе элементов.Предпочитаю String.

0 голосов
/ 11 августа 2011

Невозможно сделать эту работу для массивов символов, потому что HashMap основан на методах hashCode() и equals() ключевых объектов. И массивы наследуют реализацию Object, которая основана на идентичности, а не на содержимом, и вы также не можете их переопределить. То, что вы видите как «содержимое» карты, является выводом toString(), который для массивов также основывается на идентичности объекта, а не на контексте.

Используйте Строки, вот для чего они. Практически все API Java предназначены для работы со строками, в то время как массивы символов редко используются напрямую.

0 голосов
/ 11 августа 2011

Вы пытаетесь использовать Char Array в качестве ключа, который просто является ссылкой на объект, а просто является хэш-кодом

значение, которое вы не можете указать при получении данных с карты. поэтому лучше использовать элементы массива Char [],

, который вы можете отслеживать, чтобы получить данные позже ..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...