К. Арнольд, Д. Гослинг - Язык программирования Java (1160779), страница 50
Текст из файла (страница 50)
Конфликты хеш-кодов должны происходитькак можно реже. Хеш-коды обязаны равномерно распределяться по диапазону возможных значений, который для класса Hashtable совпадает сполным диапазоном типа int. Если различные ключи часто приводят к одним и тем же хеш-кодам, то некоторая часть хеш-таблицы быстропереполнится, в результате чего пострадает эффективность.Значение хеш-кода возвращается методом hashCode для объекта, являющегося ключом.
По умолчанию каждый объект имеет уникальный хешкод. Использование в качестве ключей случайно выбранных объектов приводит к порождению различных хеш-кодов. Классы String, BitSet ибольшинство других, переопределяющих метод equal, обычно переопределяют и hashCode. Это важно, поскольку класс Hashtable используетхеш-код для нахождения набора ключей, которые могут совпадать с заданным, и вызывает equal для каждого из таких объектов, пока не будетнайден совпадающий. Если для некоторых объектов equal и hashCode окажутся несовместимыми, то при использовании объектов этого типа вкачестве ключей Hastable их поведение окажется непредсказуемым.Пример использования класса Hastable приведен в классе Attributed Impl (см.
раздел “Реализация интерфейсов”), в котором объект Hashtableиспользован для хранения атрибутов объекта. В этом примере ключами являются строковые объекты, представляющие собой имена атрибутов, аобъекты Attr были значениями атрибутов.Кроме методов, входящих в класс Dictionary (get, put, remove, size, isEmpty, keys и elements), Hastable содержит следующие методы:public synchronized boolean containsKey(Object key)Возвращает true, если хеш-таблица содержит элемент с заданным ключом.public synchronized boolean contains(Object element)Возвращает true, если заданный element является элементом хеш-таблицы. Данная операция является более сложной, чем метод containsKey,поскольку хеш-таблица спроектирована с расчетом на эффективный поиск ключей, а не элементов.public synchronized void clear()Делает хеш-таблицу пустой.public synchronized Object clone()Создает дубликат хеш-таблицы.
Ключи и элементы при этом не дублируются.Объекты Hashtable автоматически увеличиваются, когда они становятся слишком заполненными. Под выражением “слишком заполненными”понимается превышение показателя загрузки таблицы, который представляет собой отношение количества элементов к текущей емкоститаблицы. Когда таблица увеличивается, ее новая емкость примерно вдвое превышает текущую.
Для повышения эффективности следует выбиратьемкость, представленную простым числом, чтобы при увеличении объекта Hastable также было выбрано ближайшее простое число. Исходнаяемкость хеш-таблицы и показатель загрузки могут задаваться в конструкторах Hashtable:public Hashtable()Конструирует новую, пустую хеш-таблицу с принятой по умолчанию исходной емкостью и показателем загрузки, равным 0, 75.public Hashtable(int initialCapacity)Конструирует новую, пустую хеш-таблицу с заданной емкостью initial Capacity и принятым по умолчанию показателем загрузки, равным 0,75.public Hashtable(int initialCapacity, float loadFactor)Конструирует новую, пустую хеш-таблицу с заданной емкостью и показателем загрузки loadFactor, который представляет собой число, лежащее вдиапазоне 0,0–1,0 и определяющее момент увеличения хеш-таблицы.
Если количество элементов хеш-таблицы превышает текущую емкость,умноженную на показатель загрузки, то хеш-таблица автоматически увеличивается.Емкость по умолчанию выбирается “разумной”, причем критерий разумности зависит от реализации. После конструирования объекта Hashtableневозможно изменить показатель загрузки или явно задать новую емкость.При увеличении объекта Hashtable повторное хеширование осуществляется методом rehash. Метод rehash является защищенным, так чторасширенные классы могут вызывать его по своему усмотрению, когда они решат, что наступило время увеличить емкость таблицы.
Задатьновый размер при этом невозможно — он всегда вычисляется методом rehash.При реализации метод Hashtable.toString возвращает строку, которая полностью описывает содержимое таблицы, включая результаты вызова toString для всех ключей и элементов, входящих в нее.Упражнение 12.3В классе WhichChars, имеется проблема с пометкой символов в верхней части диапазона Unicode, поскольку высокие значения символовоставляют много неиспользованных битов в нижней части диапазона. Решите эту проблему с помощью класса Hashtable, сохраняя объектCharacter для каждого обнаруженного символа.
Не забудьте написать свой класс-перечисление.Упражнение 12.4Теперь воспользуйтесь классом Hashtable, чтобы сохранять объект BitSet для каждого нового старшего байта (старшие 8 бит), встречающегося вовходной строке, причем каждый BitSet должен содержать младшие байты вместе с данным старшим байтом. Не забудьте написать свой классперечисление.Упражнение 12.5Напишите программу, которая пользуется объектом StreamTokenizer для разбиения входного файла на слова и подсчета количества слов вфайле, с выводом результата.12.8.
Класс PropertiesЕще один распространенный вариант пары ключ/элемент — список свойств, состоящий из строковых имен и связанных с ними строковыхэлементов. Эта разновидность словаря часто обладает вспомогательным набором элементов по умолчанию для свойств, отсутствующих втаблице. Класс Properties является расширением Hashtable.
Практически для всех манипуляций со списками свойств используются методыHashtable, однако для получения свойств применяется один из двух методов getProperty:public String getProperty(String key)Возвращает элемент для заданного ключа key. Если ключ отсутствует в списке свойств, просматривается список свойств по умолчанию (если онсуществует). Метод возвращает null, если свойство не найдено.public String getProperty(String key, String defaultElement)Возвращает элемент для заданного ключа key.
Если ключ отсутствует в списке свойств, просматривается список свойств по умолчанию (если онсуществует). Если элемент отсутствует в обоих списках, возвращается строка defaultElement.Класс Properties содержит два конструктора: один вызывается без аргументов, а второму передается объект Properties, который представляетвспомогательный список свойств по умолчанию. Если поиск в основном списке свойств оказывается неудачным, то просматриваетсявспомогательный объект Properties, который, в свою очередь, может иметь собственный вспомогательный объект со свойствами по умолчанию,и так далее. Цепочка основных и вспомогательных списков свойств может иметь произвольную длину.public Properties()Создает пустой список свойств.public Properties(Properties defaults)Создает пустой список свойств с заданным вспомогательным объектом Properties для поиска свойств, отсутствующих в основном списке.Если список свойств состоит только из строковых ключей и элементов, можно записывать или считывать его из файла или иного потока ввода/вывода с помощью следующих методов:public void save(OutputStream out, String header)Сохраняет содержимое списка свойств в OutputStream.
Строка header записывается в выходной поток в виде комментария, состоящего из однойстроки. Не пользуйтесь многострочными заголовками-комментариями, иначе сохраненный список свойств не удастся загрузить. В файлесохраняются только свойства, входящие в основной список, но не во вспомогательный.public synchronized void load(InputStream in) throwsIOExceptionЗагружает список свойств из InputStream.
Предполагается, что список свойств был ранее сохранен методом save. Метод загружает свойстватолько в основной список, но не во вспомогательный.Для получения объекта Enumeration, представляющего собой “фотографию” ключей в списке свойств, применяется метод propertyNames:public Enumeration propertyNames()Создает объект-перечисление с перечнем всех ключей. Метод гарантирует фиксацию исходного состояния.public void list(PrintStream out)Выводит свойства из списка в заданный поток PrintStream.
Метод полезен во время отладки.После создания объекта невозможно изменить его вспомогательный перечень свойств. Если это все же необходимо сделать, можно создатьподкласс класса Properties и изменить значение защищенного поля defaults, содержащее список свойств по умолчанию.12.9. Классы Observer/ObservableТипы Observer/Observable предоставляют протокол, в соответствии с которым произвольное количество объектов-наблюдателей Observerполучают уведомления о каких-либо изменениях или событиях, относящихся к произвольному количеству объектов Observable.