Лекция
Привет, сегодня поговорим про ассоциативные массивы java, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое ассоциативные массивы java , настоятельно рекомендую прочитать все из категории ООП и практические JAVA.
Ассоциативный массив — это набор пар элементов. Каждая пара содержит ключ и значение, причем ключи не повторяются. В любой момент можно получить элемент-значение, ассоциированный (находящийся в паре) с заданным ключом. Ассоциативный массив также называют словарем или отображением.
В виде ассоциативного массива удобно хранить, например, строку, полученную из базы данных. Ключом будет название столбца, а значением — значение этого столбца для полученной строки.
Можно воспринимать ассоциативный массив как разновидность обычного массива, в котором индексы могут быть не только целыми числами, а произвольными объектами.
Интерфейс Map
содержит методы для работы с ассоциативным массивом:
size()
— возвращает количество элементов (пар) в массиве;
containsKey(Object key)
— проверяет, существует ли в массиве элемент с ключом key
;
containsValue(Object value)
— проверяет, существует ли в массиве элемент со значением value
;
get(Object key)
— возвращает значение, соответствующее ключу key
;
put(Object key, Object value)
— добавляет в массив элемент с ключом key
и значением value
. Если элемент с таким ключом уже существует в массиве, то его значение просто изменяется;
values()
— возвращает значения всех элементов массива в виде коллекции (т.е. возвращаемый результат имеет типCollection
);
remove(Object key)
— удаляет элемент с ключом key
, возвращая значение этого элемента (если он есть) и null, если такого элемента не было;
clear()
— очищает массив;
isEmpty()
— проверяет, не пуст ли массив.
Каждый элемент ассоциативного массива, описываемого интерфейсом Map
, имеет интерфейсный тип Map.Entry
, который предоставляет три основных метода:
getKey()
— возвращает ключ элемента;
getValue()
— возвращает значение элемента;
setValue(Object value)
— меняет значение элемента.
Метод entrySet()
, определенный в интерфейсе Map
, позволят получить все элементы ассоциативного массива в виде множества объектов типа Map.Entry
.
Класс Hashtable
— одна из реализаций интерфейса Map. *
Hashtable
, как и Vector
, кроме размера имеет емкость (размер буфера, выделенного под элементы массива). Помимо этого он характеризуется показателем загруженности — долей буфера, после заполнения которой емкость автоматически увеличивается. Конструктор Hashtable()
без параметров создает пустой объект с емкостью в 101 элемент и показателем загруженности 0.75. Чтобы задать начальную емкость и показатель загруженности, следует воспользоваться конструктором с двумя параметрами Hashtable(int capacity, float loadFactor)
.
Hashtable
имеет наследника — класс Properties
, который вместо пар произвольных объектов хранит пары строк. Если в конкретной задаче и ключи и значения элементов ассоциативного массива должны иметь тип String
(а это бывает довольно часто), удобнее воспользоваться классом Properties
— не надо будет делать постоянное приведение типов.
В классе Properties
определены методы getProperty(String key)
и setProperty(String key, String value)
, работающие аналогично методам get()
и put()
, но принимающие параметры типа String
.
SortedMap
— наследник интерфейса Map
, описывает ассоциативный массив, элементы которого упорядочены по ключам. Методы, предоставляемые этим интерфейсом: firstKey()
, lastKey()
, subMap(Object fromKey, Object toKey)
,headMap(Object toKey)
, tailMap(Object fromKey)
аналогичны методам интерфейса SortedSet
. Данный интерфейс реализуется, например, в классе TreeMap
. Один из конструкторов этого класса принимает объект типа Comparator
, посредством которого можно задать свой собственный порядок сортировки.
Нужно разработать метод findUser(String login, String password)
, находящий в базе данных зарегистрированных пользователей пользователя с логином login
и паролем password
и возвращающий объект класса User
, созданный на основе информации из этой БД. Об этом говорит сайт https://intellect.icu . Метод должен возвращать null, если пользователя с требуемыми логином и паролем не существует.
Пусть сведения о зарегистрированных пользователях хранятся в таблице USERS
, имеющей следующую структуру:
Пусть уже имеется вспомогательный метод getNextUser()
, который возвращает очередную строку этой таблицы, а если строк больше нет, возвращает null. Заголовок этого метода может выглядеть следующим образом:
Map getNextUser();
Заметьте, возвращаемый результат имеет интерфейсный тип Map
, а не какого-то конкретного класса (например,Hashtable
). Это профессиональный подход к разработке метода. Конечно, внутри метода происходит работа с объектом конкретного класса (возможно, с тем же Hashtable
— ведь метод должен создать возвращаемый объект, а создать объект абстрактного класс или интерфейса нельзя). Но, скрывая детали своей реализации и сообщая остальной программе лишь минимально необходимую информацию (что возвращаемый результат поддерживает интерфейс Map
), метод добивается большей гибкости. Впоследствии может быть принято решение заменить Hashtable
на HashMap
, и при этом все изменения нужно будет произвести только в теле метода getNextUser()
, а не во всех местах программы, где он вызывался.
Ключами элементов ассоциативного массива, возвращаемого методом getNextUser()
, являются строки, совпадающие с названиями столбцов таблицы, а значениями — строки, содержащие значения из соответствующей ячейки таблицы. Предположим, что этот метод к тому же облегчает нам работу: заменяет значение 0 столбца category на строку "user", а значение 1 на строку "admin". Дело в том, что в зависимости от категории пользователя (которая в БД закодирована числом), мы должны создать либо объект класса User
, либо объект производного от него класса Admin
.
Наш метод будет выглядеть следующим образом. (Набирать его нет смысла, просто постарайтесь разобраться. И следите за скобками!)
private User findUser(String login, string password) {
Map userData = getNextUser();
while (userData != null) {
if (((String)UserData.get("login")).equals(login) &&
((String)UserData.get("password")).equals(password)) {
if (((String)UserData.get("category")).equals("user"))
return new User((String)UserData.get("name"));
if (((String)UserData.get("category")).equals("admin"))
return new Admin((String)UserData.get("name"));
}
}
userData = getNextUser();
}
return null;
}
Обратите внимание как каждый раз, обращаясь к ассоциативному массиву userData
методом get()
и получая значение, ассоциированное с нужным нам ключом, мы приводим его к типу String
.
Обратите внимание на организацию цикла while: мы вызываем метод getNextUser()
, пока он не возвратит нам значениеnull. Если в процессе обработки очередного набора данных из таблицы мы обнаружим, что логин и пароль совпадают с параметрами метода, мы завершаем работу метода командой return, возвращая требуемый объект. Если же командаreturn ни разу не вызовется в цикле, это будет означать, что такого пользователя в базе нет и метод должен вернутьnull, что он и делает в последней строке.
Объектно-ориентированный подход к описанию коллекций дает нам ряд преимуществ. В частности, возможность помещать в коллекции объекты любых классов. Но при этом простые типы данных оказываются обделенными. Мы не можем создать коллекцию целых чисел int или символов char*.
Для того, чтобы работать с простыми типами данных как с объектами (и, в частности, применять их в коллекциях), используются так называемые классы-оболочки (wrappers). Класс-оболочка построен по очень простому принципу: он хранит внутри себя поле простого типа и предоставляет несколько операций для доступа к этому полю.
В стандартной библиотеке Java определены восемь классов-оболочек — по одному на каждый простой тип. Их названия совпадают с названиями этих типов, но начинаются с заглавной буквы. То есть, это Byte
, Short
, Long
, Float
, Double
,Char
, Boolean
. Исключение — класс-оболочка для целых чисел, который называется Integer
. Каждый класс имеет простой конструктор, принимающий величину соответствующего типа.
Integer i = new Integer(15);
Boolean b = new Boolean(false);
При необходимости легко можно получить «содержимое» класса с помощью одного из его методов. Автоматического приведения к простому типу не происходит. Так что, если нам надо передать в какой-то метод параметр типа int, а нужное нам число представляет собой объект класса Integer
, надо осуществить явное преобразование:
String s;
сhar ch = s.charAt(i.intValue);
Зато легко теперь добавлять объекты простых типов в любую коллекцию. Например:
Vector vect = new Vector();
vect.add(b);
vect.add(new Double(3.14));
Класс Vector
в последних версиях Java позволяет передавать в метод и примитивные типы данных, автоматически создавая для них оболочку.
Данные типа дата/время приходится обрабатывать довольно часто, поэтому все современные языки программирования предлагают удобный механизм для работы с ними в одной из своих библиотек.
В Java для этих целей разработаны классы Date
и Calendar
, собранные в пакете java.util.
Класс Date
хранит число миллисекунд, прошедших с 1 января 1970 года (во внутреннем поле, имеющем тип long). Конструктор без параметров этого класса создает объект, содержащий текущее время (по системным часам машины, на которой выполняется программа). Другой конструктор, с параметром типа long, создает объект Date
на основе заданного числа.
Метод getTime()
позволяет получить это число, а метод setTime(long newTime)
— изменить.
Для отображения даты на экране ее внутреннее представление необходимо перевести в строку, более удобную для восприятия. Для этого обычно используется класс SimpleDateFormat
(являющийся наследником абстрактного классаDateFormat
), который надо импортировать из пакета java.text. Прежде всего необходимо создать объект этого класса, указав в качестве параметра конструктора строку, определяющую способ форматирования. Например:
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy hh:mm");
Теперь следует вызвать метод format()
созданного форматирующего объекта, передав ему в качестве параметра тот объект Date
, который мы хотим представить в виде строки. Чтобы вывести на экран текущую дату, используем команду:
System.out.println(formatter.format(new Date()));
В момент написания этих строк программа вывела в консоль
23.09.2007 05:51
В строке "dd.MM.yyyy hh:mm" dd
означает цифры дня, MM
— цифры месяца, yyyy
— цифры года, hh
— часы и mm
— минуты. Комбинация MMMM
дала бы название месяца (в именительном падеже), а yy
— только две последние цифры года. Названные составляющие могут следовать в любом порядке (причем, все они присутствовать не обязаны), а разделители между ними (в примере это точка, пробел и двоеточие) могут быть и другими.
Класс Calendar
позволяет работать с датой на более высоком уровне, отдельно рассматривая составляющие даты (число, месяц, год и т.д.). Он является абстрактным, поэтому необходимо пользоваться одним из его наследников. Таковым является GregorianCalendar
(описывающий грегорианский календарь, по которому мы живем).
Создать объект этого класса, содержащий текущую дату/время можно конструктором без параметров. Всего же у классаGregorianCalendar
семь конструкторов, наиболее мощный из них принимает шесть параметров:
GregorianCalendar(int year, int month, int day, int hour, int minutes, int seconds)
Получить любую часть даты можно с помощью универсального метода get(int field)
. Целочисленный параметр field
определяет желаемую часть даты.
В классе Calendar
определены константы, описывающие возможные варианты: ERA, YEAR, MONTH, WEEK_OF_YEAR, WEEK_OF_MONTH, DAY_OF_YEAR, DAY_OF_MONTH, DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND
и несколько других.
Например, узнаем, какой сегодня день года:
GregorianCalendar today = new GregorianCalendar();
int result = today.get(Calendar.DAY_OF_YEAR);
System.out.println(result);
Любую часть даты можно изменить методом set(int field, int value)
.
Спроектируйте и разработайте метод, определяющий, сколько времени прошло с заданной даты. С помощью этого методы выведите в консоль, сколько времи прошло с вашего дня рождения в удобном для восприятия виде, например: «Вам исполнилось 20 лет, 3 месяца, 18 дней, 4 часа, 5 минут и 10 секунд».
В пакете java.util описан класс Random
, являющийся генератором случайных чисел. На самом деле в силу своей природы ЭВМ не может генерировать истинно случайные числа. Числа генерируются определенным алгоритмом, причем каждое следующее число зависит от предыдущего, а самое первое — от некоторого числа, называемого инициализатором. Две последовательности «случайных» чисел, сгенерированных на основе одного инициализатора, будут одинаковы.
Класс Random
имеет два конструктора:
Random()
— создает генератор случайных чисел, использующий в качестве инициализатора текущую дату (число миллисекунд с 1 января 1970);
Random(long seed)
— создает генератор случайных чисел, использующий в качестве инициализатора число seed
.
Рекомендуется использовать первый конструктор, чтобы генератор выдавал разные случайные числа при каждом новом запуске программы.
От генератора можно получать случайные числа нужного типа с помощью методов nextBoolean()
, nextInt()
,nextLong()
, nextFloat()
, nextDouble()
. Вещественные числа генерируются в диапазоне от 0 до 1 (не включая 1), а целые — из всего диапазона возможных значений. Можно сгенерировать целое число в нужном диапазоне (от 0 до max-1
) методом nextInt(int max)
или nextLong(long max)
.
Наконец, можно заполнить случайными числами целый массив (предварительно созданный), воспользовавшись методомnextBytes(byte[] arr)
. Элементы массива arr
должны иметь тип byte
.
На этом все! Теперь вы знаете все про ассоциативные массивы java, Помните, что это теперь будет проще использовать на практике. Надеюсь, что теперь ты понял что такое ассоциативные массивы java и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории ООП и практические JAVA
Комментарии
Оставить комментарий
ООП и практические JAVA
Термины: ООП и практические JAVA