Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
JAVA_programming_Gorban / JAVA_programming_Gorban.pdf
Скачиваний:
41
Добавлен:
23.02.2016
Размер:
14.53 Mб
Скачать

99

Програмування у Java

Урок 6. Класи-коллекції

Клас Vector

Як створити вектор

Як додати елемент у вектор

Як замінити елемент

Як узнати розмір вектора

Як звернутися до элементу вектора

Як узнати, чи єсть елемент у векторі

Як узнати індекс елементу

Як видалити елементи

Клас Stack

Клас Hashtable

Як створити таблицю

Як заповнити таблицю

Як одержати значення по ключу

Як узнати наявність ключа або значення

Як одержати всі елементи таблиці

Як видалити елементи

Клас Properties

Інтерфейс Collection

Інтерфейс List

Інтерфейс Set

Інтерфейс SortedSet

Інтерфейс Map

Інтерфейс Map.Entry

Інтерфейс SortedMap

Абстрактні класи-колекеції

Інтерфейс Iterator

Інтерфейс ListIterator

Класи, що створюють списки

Двонаправленний список

Класи, що створюють відображення

Упорядковані відображення

Порівняння елементів колекцій

Класи, що створюють множини

Упорядковані множини

Дії з колекціями

Методи класу Collections

Заключення

100

Влістинзі 5.1ми розібрали рядок на слова. Як їх зберегти для подальшої обробки? До сих пір ми користувалися масивами. Вони зручні, якщо треба швидко обробити однотипні елементи, наприклад, просумувати числа, знайти найбільше і найменше значення, посортувати елементи. Але вже для пошуку потрібних даних у великому обємі інформації масиви незручні. Для цього краще використовувати бінарні дерева пошуку. Крім того, масиви завжди мають постійну, наперед задану довжину, в масив незручно додавати елементи. При видаленні елемента із масиву решту елементів треба перенумерувати. При вирішенні задач, в яких кількість элементів заздалегідь невідома, елементи треба часто видаляти і додавати, треба шукати інші способи зберігання. В мові Java з самих перших версій єсть клас Vector, призначений для зберігання зміннного числа елементів самого загальногого типу Оbject.

6.1.Клас Vector

Вкласі Vector із пакету java.utiІ зберігаються елементи типу Оbject, а значить, довільного типу. Кількість елементів може бути довільним і наперед не визначається. Елементи одержують індекси 0, 1, 2, .... До кожного элемента вектора можна звернутися по індексу, як і до елемента массиву. Крім кількості елементів, яку називають розміром (size) вектора, єсть ще розмір буферу — ємність (capacity) вектора. Звичайно ємність співпадає з розміром вектора, але можна її збільшити методом ensureCapacity(int minCapacity) або порівняти з розміром вектора методом trimToSize(). В Java 2 клас Vector перероблений, щоб включити його в ієрархію класів-колекцій. Тому багато дій можна робити старими и новими методами. Рекомендується використовувати нові методи, оскільки старі можуть бути виключені із наступних версій Java.

6.1.1.Як створити вектор

Вкласі чотири конструктори:

Vector () - створює пустий обєкт нульової довжини;

Vector (int capacity) - створює пустий обєкт указаної ємності capacity;

Vector (int capacity, int increment) - створює пустий обєкт указаної ємності capacity і задає число increment, на яке збільшується ємність при необхідності;

Vector (Collection с) - вектор створюється по указаній колекції. Якщо capacity відємне, створюється виключна ситуація. Після створення вектору його можна заповняти елементами.

6.1.2.Як додати елемент у вектор

Метод add (Object element) дозволяє додати елемент в кінець вектора (те ж саме робить старий метод addElement (Object element).

Методом add (int index, Object element) або старим методом insertElementAt (Object element, int index) можна вставити елемент у вказане місце index. Елемент, що знаходиться на цьому місці, і всі наступні элементи здвигаються, їх індекси збільшуються на одиницю.

Метод addAІl (Collection coll) дозволяє додати в кінець вектора всі елементи коллекції coll.

Методом addAІІ(int index, Collection coll) можна вставити в позицію index всі елементи коллекції coll.

6.1.3.Як замінити елемент вектора

Метод set (int index, object element) заміняє елемент, що стоїть у векторі в позиції index, на елемент element (те ж саме дозволяє виконувати старий метод setElementAt (Object element, int index))

6.1.4. Як узнати розмір вектора

Кількість елементів у векторі завжди можна взнати методом size(). Метод capacity() повертає ємність вектора. Логічний метод isEmpty() повертає true, якщо у векторі немає жодного элемента.

6.1.5. Як звернутися до елемента вектора

Звернутися до першого элементу вектора можна методом firstEiement(), до останнього - методом lastEІement(), до довільного элементу - методом get (int index) або старим методом elementAt (int index). Ці

101

методи повертають обєкт класу Оbject. Перед використанням його треба привести до потрібного типу. Одержати всі елементи вектора у вигляді масиву типу object[] можна методами toArray() і toArray (Object [] а). Другий метод заносить всі елементи вектора в масив а, якщо в ньому достатньо місця.

6.1.6. Як узнати, чи єсть елемент у векторі

Логічний метод contains (object element) повертає true, якщо елемент element знаходиться у векторі.

Логічний метод containsAІІ (Collection с) повертає true, якщо вектор містить всі элементи указаної колекції.

6.1.7. Як узнати індекс елемента

Чотири методи дозволяють знайти позицію указаного елемента element:

indexof (Object element) - повертає індекс першої появи элемента у векторі;

indexOf (Object element, int begin) - веде пошук, починаючи з індекса begin включно;

lastІndexOf (object element) - повертає індекс останньої появи елемента у векторі;

lastІndexOf (Object element, int start) - веде пошук від індекса start включно до початку вектора.

Якщо елемент не знайдено, повертається -1.

6.1.8. Як видалити елементи вектора

Логічний метод remove (Object element) видаляє із вектора перше входження указаного елемента element. Метод повертає true, якщо елемент знайдено і видалення виконано.

Метод remove (int index) видаляє елемент із позиції index і повертає його в якості свого результату типу Оbject. Аналогічні дії дозволяють ввиконати старі методи типу void: removeElement (Object element) і removeElementAt (int index), що не повертають результату.

Видалити діапазон елментів можна методом removeRange(int begin, int end). Видаляються елементи від позиції begin включно до позиції end виключно.

Видалити із даного вектора всі елементи колекції coil можна логічним методом removeAll(Collection coll). Видалити останні елементи можна, просто урізавши вектор методом setSizefint newSize).

Видалити всі елементи, крім тих, що входять у вказану колекцію coil, дозволяє логічний метод retainAll(Collection coll). Видалити всі елементи вектора можна методом clear() або старим методом removeAІІElements() або обнуливши розмір вектора методом setSize(0).

Лістинг 6.1 розширює лістинг 5.1, обробляючи виділені із рядка слова за допомогою вектора.

Лістинг 6.1. Робота з вектором

import java.util.*; class Parse{

public static void main(String[] args){ Vector v = new Vector();

String s = "String, that we want to decompose in words."; StringTokenizer st = new StringTokenizer(s, " \t\n\r,.");

while (st.hasMoreTokens()){

// Одержуємо слово і заносимо у вектор v.add(st.nextToken()); // Додаємо в кінець вектора

}

System.out.println(v.firstElement()); // Перший елемент System.out.println(v.lastElement()); // Останній елемент v.setSize(4); // Зменшуємо число елементів v.add("compose"); // Додаємо в кінець вкороченого вектора v.set(3, "again"); // Ставимо в позицію 3

102

for (int i = 0; i < v.size(); i++)// Перебираємо весь вектор System.out.print(v.get(i) + " ");

System.out.println();

}

}

Клас Vector являється прикладом того, як можна обєкти класу Оbject, a значить, будь-які обєкти, обєдувати в колекцію. Цей тип колекції упорядковує і навіть нумерує елементи. У векторі єсть перший елемент, єсть останній елемент. До кожного элементу звертаються безпосередньо по індексу. При додаванні і увидаленні елементів решта елементівы автоматично перенумеровуються.

Передивіться файл Vector у папці java.util і визначте, чи всі методи цього класу були задіяні у попередній програмі.

Другий приклад колекції — клас Stack — розширяє клас Vector.

6.2. Клас Stack

Клас Stack із пакету java.utiІ обєднує елементи в стек. Стек (stack) реалізує порядок роботи з елементами подібно магазину гвинтівки— першим вистрелить патрон, покладений в магазин останнім,— або подібно залізничному тупику — першим із тупика вийде вагон, загнаний туди останнім. Такий порядок обробки називається LIFO (Last In — First Out).

Перед работою створюється пустий стек конструктором Stack (). Потім на стек кладутся і знімаються елементи, причому доступний тільки "верхній" елемент, той, що покладений на стек останнім. Додатково до методів класу Vector клас Stack містить пять методів, що дозволяють працювати з колекцією як зі стеком:

push (Object item) —поміщає елемент item в стек;

pop () - дістає верхній элемент зі стека;

peek () - читає верхній елемент, не дістаючи його зі стека;

empty () - перевіряє, чи не пустий стек;

search (object item) - знаходить позицію элемента item в стеку. Верхній елемент має позицію 1, під ним елемент 2 і т. д. Якщо елемент не знайдено, повертається - 1.

Лістинг 6.2 показує, як можна використовувати стек для перевірки парності символів.

Лістинг 6.2. Перевірка парності дужок

import java.util.*; class StackTest{

static boolean checkParity(String expression, String open, String close){

Stack stack = new Stack ();

StringTokenizer st = new StringTokenizer(expression, " \t\n\r+*/-(){}", true); while (st.hasMoreTokens ()) {

103

String tmp = st.nextToken();

if (tmp.equals(open)) stack.push(open); if (tmp.equals(close)) stack.pop();

}

if (stack.isEmpty () ) return true; else

return false;

}

public static void main(String[] args){ System.out.println(

checkParity("a - (b - (c - a) / (b + c) - 2" , "(", ")"));

}

}

Передивіться файл Stack у папці java.util і визначте, чи всі методи цього класу були задіяні у попередній програмі.

Як бачимо, колекції значно полегшують обробку наборів даних. Ще один приклад колекції зовсім іншого роду - таблиці — представляє клас Hashtable.

6.3. Класс Hashtable

Класс Hashtable розширяє абстрактний клас Dictionary. В обєктах цього класу зберігаються пари "ключ - значення". Із таких пар "Прізвище І. Б. — номер" складається, наприклад, телефонний довідник. Ще один приклад - анкета. Її можна представить як сукупність пар "Прізвище - Іванов", "Імя — Петро", "По батькові - Сидорович", "Рік нарождення — 1975" і т. д. Подібних прикладів можна привести багато. Кожний обєкт класу Hashtable крім розміру (size) - кількості пар, має ще дві характеристики: ємність (capacity) - розмір буферу, і показник завантаженості (load factor) — процент заповнення буферу, по досягненні якого збільшується його розмір.

6.3.1. Як створити таблицю

Для створення обєктів клас Hashtable має чотири конструктори:

Hashtable () - створює пустий обєкт з початковою ємністю в 101 елемент і показником завантаженості 0,75;

Hashtable (int capacity) - створює пустий обєкт з початковою ємністю capacity і показником завантаженості 0,75;

Hashtable(int capacity, float loadFactor) - створює пустий обєкт з початковою ємністю capacity і

показником завантаженості loadFactor;

Hashtable (Map f) - створює обєкт класу Hashtable, що містить всі елементи відображення f, з ємністю, рівною подвоєному числу элементів відображеня f, але не менше 11, і показником завантаженості 0,75.

6.3.2. Як заповнити таблицю

Для заповнення обєкту класу Hashtable використовуются два методи:

Object put(Object key, Object value) — додає пару "key— value", якщо ключа key не було в таблиці, і

змінює значення value ключа key, якщо він уже єсть в таблиці. Повертає старе значення ключа

104

або null, якщо його не було. Якщо хоч би один параметр рівний null, виникає виключна ситуація;

void putAІІ(Map f) — додає всі элементи відображення f. В обєктах-ключах key повинні бути реалізовані методи hashCode() і equals ().

6.3.3. Як одержати значення по ключу

Метод get (Object key) повертає значення елемента з ключем key у вигляді обєкта класу object. Для подальшої роботи його треба перетворити в конкретний тип.

6.3.4. Як узнати наявність ключа або значення

Логічний метод containsKey(object key) повертає true, якщо в таблиці єсть ключ key.

Логічний метод containsValue (Object value) або старий метод contains (Оbject value) повертає true,

якщо в таблиці єсть ключі із значенням value.

Логічний метод isEmpty() повертає true, якщо в таблиці немає элементів.

6.3.5. Як одержати всі елементи таблиці

Метод values() представляє всі значення value таблиці у вигляді інтерфейсу Collection. Всі модифікації в обєкті Сollection змінюють таблицю, і навпаки.

Метод keyset() представляє всі ключі key таблиці у вигляді інтерфейсу Set. Всі зміни в обєкті Set коректують таблицю, і навпаки.

Метод entrySet() представляє всі пари "key— value" таблиці у вигляді інтерфейсу Set. Всі зміни в обєкті Set коректують таблицю, і навпаки.

Метод toString() повертає рядок, що містить всі пари.

Старі методи elements() і keys() повертають значення і ключі у вигляді інтерфейсу Enumeration.

6.3.6. Як видалити елементи

Метод remove (Object key) видаляє пару с ключем key, повертаючи значення цього ключа, якщо воно єсть, і null, якщо пара з ключем key не знайдена.

Метод clear() видаляє всі елементи, очищаючи таблицю.

Влістинзі 6.3 показано, як можна використати клас HashtabІe для створення телефонного довідника, а на рис. 6.1 — виведення цієї програми.

Лістинг 6.3. Телефонний довідник

import java.util.*; class PhoneBook{

public static void main(String[] args){ Hashtable yp = new Hashtable();

String name = null; yp.put("John", "123-45-67"); yp.put ("Lemon", "567-34-12"); yp.put("Bill", "342-65-87"); yp.put("Gates", "423-83-49"); yp.put("Batman", "532-25-08"); try{

name = args[0];

}

catch(Exception e){

System.out.println("Usage: Java PhoneBook Name"); return;

}

if (yp.containsKey(name))

System.out.println(name + "'s phone = " + yp.get(name)); else

System.out.println("Sorry, no such name");

105

}

}

Передивіться файл Hashtable у папці java.util і визначте, чи всі методи цього класу були задіяні у

попередній програмі.

Рис. 6.1. Робота з телефонною книгою

6.4. Класс Properties

Клас Properties розширяє клас HashtabІe. Він призначений в основному для введення і виведення пар властивостей системи і їх значень. Пари зберігаються у вигляді рядків типу String. В класі Properties два конструктори:

Properties () - створює пустий обєкт;

Properties (Properties default) - створює обєкт із заданими парами властивостей default.

Крім унаслідуваних від класу HashtabІe методів в класі Properties єсть ще наступні методи. Два методи, що повертають значення ключа-рядка у вигляді рядка:

String getProperty (string key) - повертає значення по ключу key;

String getProperty(String.key, String defaultValue) - повертає значення по ключу key; якщо такого ключа немає, повертається defaultValue.

Метод setProperty(String key, String value) додає нову пару, якщо ключа key немає, і змінює значення, якщо ключ key єсть.

Метод load(InputStream in) завантажує властивості із вхідного потоку in.

Методи list(PrintStream out) і list (PrintWriter out) виводять властивості у вихідний потік out.

Метод store (OutputStream out, String header) виводить властивості у вихідний потік out із заголовком header.

Дуже простий лістинг 6.4 і рис. 6.2 демонструють виведення всіх системних властивостей Java.

Лістинг 6.4. Виведення системних властивостей

class Prop{

public static void main(String[] args){ System.getProperties().list(System.out);

}

}

106

Передивіться файл Properties у папці java.util і визначте, як ще можна використати цей клас.

Рис. 6.2. Системні властивості

Приклади класів Vector, Stack, HashtabІe, Properties показують зручності класів-колекцій. Тому в Java 2 розроблена ціла ієрархія колекцій. Вона показана на рис. 6.3. Курсивом записані імена інтерфейсів. Пунктирні лінії вказують класи, що реалізують ці інтерфейси. Всі колекції розбиті на три групи, описані в інтерфейсах List, Set і Map.

Рис. 6.3.

Ієрар

хія

класі в і інтер фейс івколе кцій

Прик

ладо

м

реалі

зації

інтер

фейс

у List може служить клас Vector, прикладом реалізації інтерфейсу Мар — класс

HashtabІe. Колекції List і Set

мають багато спільного, тому їх спільні методи обєднані і

107

винесені в суперінтерфейс Collection. Подивимось, що, на думку розробників Java API, повинно міститися в цих колекціях.

6.5. Інтерфейс Collection

Інтерфейс Сollection із пакету java.util описує загальні властивості колекцій List і Set. Він містить методи додавання і видалення элементів, перевірки и перетворення елементів:

boolean add(Object obj) - додає елемент obj в кінець колекції; повертає false, якщо такий елемент в колекції уже єсть, а колекція не допускає повторних элементів; повертає true, якщо додавання пройшло успішно;

boolean addAІІ(Collection coll) - додає всі елементи колекції coll в кінець даної колекції;

void clear() - видаляє всі элементи колекції;

boolean contains(Object obj) - перевіряє наявність элементу obj в колекції;

boolean containsAll(Collection coll) - перевіряє наявність всіх элементів колекції coll в даній колекції;

boolean isEmpty() - перевіряє, чи колекція пуста ;

iterator iterator() - повертає ітератор даної колекції;

boolean remove(object obj) — видаляє указаний елемент із колекції; повертає false, якщо елемент не знайдено, true, якщо видалення пройшло успішно;

boolean removeAІІ (Collection coll) — видаляє елементи указаної колекції, що належать даній колекції;

boolean retainAІІ(Collection coll) - видаляє всі елементи даної колекції, крім елементів колекції coll;

int size() - повертає кількість елементів в колекції;

Оbject [] toArray () - повертає всі елементи колекції у вигляді масиву;

Object[] toArray<object[] a - записує всі елементи колекції в массив а, якщо в ньому достатньо місця.

Передивіться файл java.utiІ\Interfaces\Collection.

6.6. Інтерфейс List

Інтерфейс List із пакету java.utiІ, що розширює інтерфейс Collection, описує методи роботи з упорядкованими колекціями. Інколи їх називають послідовностями (sequence). Елементи такої колекції перенумеровані, починаючи з нуля, до них можна звернутися по індексу. На відміну від колекції Set елементи колекції List можуть повторятися. Клас Vector — одна із реалізацій інтерфейсу List. Інтерфейс List додає до методів інтерфейсу Collection методи, що використовують індекс index елемента:

void add(int index, object obj) - вставляє елемент obj в позицію index; старі елементи, починаючи з позиції index, зсуваються, їх індекси збільшуються на одиницю;

boolean addAll(int index, Collection coll) - вставляє всі елементи колекції coІl;

object get(int index) - повертає елемент, що знаходиться в позиції index;

int indexOf(Object obj) - повертає індекс першої появи елемента obj в коллекції;

int lastІndexOf (object obj) - повертає індекс останньої появи елемента obj в колекції;

ListІterator listiterator () - повертає ітератор колекції;

ListІterator listiterator (int index) — повертає ітератор кінця колекції від позиції index;

object set (int index, object obj) — заміняє елемент, що знаходиться в позиції index, елементом obj;

List subList(int from, int to) — повертає частину коллекції від позиції from включно до позиції to виключно.

Передивіться файл java.utiІ\Interfaces\List.

6.7. Інтерфейс Set

Інтерфейс Set із пакету java.utiІ розширює інтерфейс Collection, описуючи неупорядковану колекцію, яка не містить повторюваних елементіов. Це відповідає математичному поняттю множини (set). Такі колекції зручні для перевірки наявності або відсутності у елемента властивості, що визначає множину. Нові методи в інтерфейс Set не додані, просто метод add () не стане додавати ще одну копію елемента, якщо такий елемент уже єсть в множині. Цей інтерфейс расширюється інтерфейсом SortedSet.

108

Передивіться файл java.utiІ\Interfaces\Set.

6.8. Інтерфейс SortedSet

Інтерфейс SortedSet із пакету java.utiІ, розширює інтерфейс Set і описує упорядковану множину, відсортовану по природному порядку зростання його елементів або по порядку, заданому реалізацією інтерфейсу comparator. Елементи не нумеруються, але єсть поняття першого, останнього, більшого і меншого элемента. Додаткові методи інтерфейсу відображають ці поняття:

comparator comparator() - повертає спосіб упорядкування колекції; Object first () - повертає перший, менший елемент колекції;

SortedSet headset(Object toElement) — повертає початкові, менші елементи до елементу toEІement

виключно;

object last() - повертає останній, більший елемент колекції;

SortedSet subset(Object fromElement, Object toEІement) - повертає підмножину колекції від елемента fromElement включно до елемента toEІement виключно;

SortedSet tailSet(Object fromElement) - повертає останні, більші елементи колекції від елемента fromElement включно.

Передивіться файл java.utiІ\Interfaces\SortedSet.

6.9. Інтерфейс Map

Інтерфейс Map із пакету java.utiІ описує колекцію, що складається із пар "ключ — значення". У кожного ключа тільки одне значення, що відповідає математичному поняттю однозначної функції або відображення (mар). Таку колекцію часто називають ще словником (dictionary) або асоціативним масивом (associative array). Звичайний масив — найпростіший приклад словника із заздалегідь заданим числом елементів. Це відображення множини перших невідємних цілих чисел на множину элементів масиву, множина пар "індекс масиву - елемент масиву". Клас HashTable - одна із реалізацій інтерфейсу Мар. Інтерфейс Map містить методи, що працюють з ключами і значеннями:

boolean containsKey(Object key) - перевіряє наявність ключа key;

boolean containsValue(Object value) - перевіряє наявність значення value;

Set entryset() — представляє колекцію у вигляді множини, кожний елемент якого — пара із даного відображення, з якою можна працювати методами вкладеного інтерфейсу Map. Entry;

Оbject get(Object key) - повертає значення, відповідне ключу key;

Set keyset() - представляє ключі колекції у вигляді множини;

Object put(Object key, Object value) — додає пару "key— value", якщо такої пари не було, і заміняє значення ключа key, якщо такий ключ уже єсть в колекції;

void putAІІ(Map m) - додає до колекції всі пари із відображення m;

Соllection values() - представляє всі значення у вигляді колекції.

Вінтерфейс Мар вкладений інтерфейс Map.Entry, який містить методи роботи з окремою парою.

Передивіться файл java.utiІ\Interfaces\Map.

6.10. Вкладений інтерфейс Map.Entry

Цей інтерфейс описує методи роботи з парами, отриманими методом entrySet():

методи getKey() і getVaІue() дозволяють отримати ключ і значення пари;

метод setVaІue(Оbject value) змінює значення в даній парі.

Передивіться файл java.utiІ\Interfaces\Map.Entry

6.11. Інтерфейс SortedMap

109

Інтерфейс SortedMap, розширює інтерфейс Map і описує впорядковану по ключах колекцію Мар. Сортування відбувається або в природному порядку зростання ключів, або, в порядку, описаному в інтерфейсі Comparator. Елементи не нумеруються, але єсть поняття більшого і меншого із двох елементов, першого, самого маленького, і останнього, самого більшого елемента коллекції. Ці поняття описуються наступними методами:

Сomparator comparator () - повертає спосіб упорядочення коллекції;

Оbject firstKey() - повертає перший, найменший елемент колекції;

SortedMap headMap(Object toKey) - повертає початок колекції до елемента з ключем toKey виключно;

Оbject lastKey() - повертає останній, найбільший ключ колекції;

SоrtedMap subMap (Object fromKey, Object toKey) - повертає частину колекції від елемента з ключем fromKey включно до елемента з ключем toKey виключно;

SortedMap taІІMap(Оbject fromKey) - повертаєт остачу колекції від элементу fromKey включно.

Ви можете створювати свої коллекції, реалізувавши розглянуті інтерфейсы. Це справа важка, оскільки в інтерфейсах багато методів. Щоб полегшити цю задачу, в Java API введені частинні реалізації інтерфейсов — абстрактні класи-колекції.

Передивіться файл java.utiІ\Interfaces\SortedMap.

6.12. Абстрактні класи-колекції

Ці класи лежать в пакеті java.util.

Абстрактний клас AbstractGollection реалізує інтерфейс Collection, але залишає нереалізованими методи iterator(), size().

Абстрактний клас AbstractList реалізует інтерфейс List, але залишає нереалізованным метод get() і наслідуваний метод size(). Цей клас дозволяє реалізувати колекцію з прямим доступом до элементів, подібно масиву

Абстрактний клас AbstractSequеntіаІList реалізує інтерфейс List, але залишає нереалізованим метод listІterator(іnt index) і наслідуваний метод size(). Даний клас дозволяє реалізувати колекцію з послідовним доступом до елементів за допомогою ітератора ListІterator.

Абстрактний клас AbstractSet реалізує інтерфейс Set, але залишає нереалізованими методи,

наслідувані від AbstractCollection.

Абстрактний клас AbstractMap реалізує інтерфейс Map, але залишає нереалізованим метод entrySet().

Нарешті, в складі Java API єсть повністю реалізовані класи-колекції помимо уже розглянутих класів

Vectоr, Stack, Hashtable і Properties. Це класи ArrayList, LinkedList, HashSet, TreeSet, HashMap, TreeMap, WeakHashMap. Для роботи з цими класами розроблені інтерфейси Іterator, ListІterator, Comparator і класи Arrays та Collections. Перед тим як розглянути використання даних класів, обговоримо поняття ітератора.

6.13. Інтерфейс Iterator

В 70—80-х роках минулого століття, після того як була усвідомлена важливість правильної організації даних у певну структуру, велика увага приділялась вивченню і побудові різних структур даних: звязаних списків, черг, деків, стеків, дерев, мереж. Разом з розвитком структур даних розвивались і алгоритми роботи з ними: сортування, пошук, обхід, хешування. Цим питанням присвячена обширна література. В 90-х роках було вирішено заносити дані в певну колекцію, заховавши її внутрішню структуру, а для роботи з даними використовувати методи цієї колекції. Зокрема, завдання обходу поклали на саму колекцію. В Java API введений інтерфейс Іterator, який описує спосіб обходу всіх елементів колекції. В кожній колекції єсть метод Іterator(), який повертає реалізацію інтерфейса Іterator для вказаної колекції. Отримавши цю реалізацію, можна обходити колекцію в деякому порядку, визначеним даним ітератором, за допомогою методів, описаних в інтерфейсі Іterator і реалізованих в цьому ітераторі. Подібна техніка використана в класі StringTokenizer. В інтерфейсі Іterator описані всього три методи:

логічний метод hasNext() повертає true, якщо обхід ще не завершено;

метод next() робить поточним наступний елемент коллкції і повертає його у вигляді обєкта класу

110

Оbject;

метод remove() видаляє поточний елемент колекції.

Можна представити собі справу так, що ітератор — це покажчик на елемент колекції. При створенні ітератора покажчик установливаетюється перед першим елементом, метод next() переміщує показчик на перший елемент і показує його. Наступне застосування методу next() переміщає показчик на другий елемент колекції і показує його. Останнє застосування методу next() виводить показчик за останній елемент колекції. Метод remove(), здається, лишній, він уже не відноситься до завдання обходу колекції, але дозволяє при перегляді коллекцї видалити із нього непотрібні елементи.

В лістинзі 6.5 до тексту лістинга 6.1 додана робота з ітератором.

Лістинг 6.5. Використання ітератора вектора

import java.util.*; class Vect {

public static void main(String[] args){ Vector v = new Vector();

String s = "String, that we want to decompose in words."; StringTokenizer st = new StringTokenizer(s, " \t\n\r,."); while (st.hasMoreTokens()){

// Одержуємо слово і заносимо у вектор. v.add(st.nextToken()); // Додаємо в кінець вектора } System.out.println(v.firstElement());// Перший елемент System.out.println(v.lastElement()); // Останній елемент v.setSize(4); // Зменшуємо число елементів v.add("compose."); // Додаємо в кінці скороченого вектора v.set(3, "again"); // Ставимо в позицію 3

for (int i = 0; i < v.size(); i++) // Перебираємо увесь вектор System.out.print(v.get(i) + ".");

System.out.println();

Iterator it = v.iterator (); // Одержуємо ітератор вектора try{

while(it.hasNext())// Доки у векторі єсть елементи, System.out.println(it.next());// виводимо поточний элемент }catch(Exception e){}

}

}

}

Запустіть програму на виконання і ретельно проаналізуйте результат.

6.14. Інтерфейс Listlterator

Інтерфейс ListІterator розширює інтерфейс Іterator, забезпечуючи переміщення по колекції як в прямому, так і в зворотному напрямі. Він може бути реалізований лише в тих колекціях, в яких єсть поняття наступного і попереднього елемента і де елементи пронумеровані. В інтерфейс ListІterator додані наступні методи:

void add(Object element) - додає eлемент element перед поточним елементом;

boolean hasPrevious() - повертає true, якщо в колекції єсть елементи, що стоять перед поточним елементом;

int nextІndex() - повертає індекс поточного елемента; якщо поточним являється останій елемент колекції, повертає розмір колекції;

Object previous() - повертає попередній елемент і робить його поточним;

int previousІndex() - повертає індекс попереднього елемента;

void set(Object element) - замінює поточний елемент елементом element - виконується зразу після next() або previous().

111

Як бачимо, ітератори можуть змінювати колекцію, в якій вони працюють, додаючи, видаляючи і заміняючи елементи. Щоб це не приводило до конфліктів, передбачена виключная ситуація, яка виникає при намаганні використовувати ітератори паралельно "рідним" методам колекції. Якраз тому в лістинзі 6.5 дії з ітератором заключені в блок try{}catch(){}.

Змінимо закінчення лістингу 6.5 з використанням ітератора ListІterator.

//Текст лістинга 6.1...

//...

ListIterator lit = v.listIterator(); // Одржуємо ітератор вектора

//Показчик зараз знаходиться перед початком вектора

try{

while(lit.hasNext()) // Доки у вектора єсть елементи System.out.println(lit.next());//Переходимо до наступного элемента і виводимо його

//Тепер показчик за кінцем вектора. Перейдемо в початок

while (lit. hasPrevious ())

System, out. println(lit. previous()); : }catch (Exception e) {}

Цікаво, що повторне використання методів next() і previous() один за другим буде видавати один і той же поточний елемент. Подивимось тепер, які можливості представляють класи-коллекції Java 2.

6.15. Класи, що створюють списки

Клас ArrayList повністю реалізує інтерфейс List і ітератор типу iterator. Клас ArrayList дуже схожий на клас Vector, має той же набір методів і може використовуватися в тих же ситуаціях. В класі ArrayList три конструктори:

ArrayList () - створює пустий объект;

ArrayList (Collection coll) - створює обєкт, який містить всі елементи колекції coll;

ArrayList (int inіtCapacity) - створює пустий обєкт ємності initCapacity.

Єдина відмінність класу ArrayList від класу Vector заключається в тому, що класс ArrayList не синхронізований. Це означає, що одночаснa зміна экземпляру цього класу декількома підпроцесами приведе до непередбачуваних результатів. Ці питання розглянемо в уроці 17.

6.16. Двонапрвлений список

Клас LinkedList повністю реалізує інтерфейс List і містить додаткові методи, що перетворюють його в двонаправлений список. Він реалізує ітератори типу iterator i bistiterator. Цей клас можна використовувати для обpобки елементів в стеку, деку або двонаправленому списку. В класі LinkedList два конструктори:.

LinkedList - створює пустий обєкт

LinkedList (Collection coll) — створює обєкт, що містить всі елементи колекції coll.

6.17. Класи, що створюють відображення

Клас HashMap повністю реалізує інтерфейс Map, а також ітератор типу iterator. Клас HashMap дуже схожий на клас HashtabІe і може використовуватися в тих же ситуаціях. Він має той же набір функцій і такі

жконструктори:

HashMap() - створює пустий обєкт з показником завантаженості 0,75;

НаshМар(int capacity) - створює пустий обєкт з початковою ємністю capacity і показником завнтаженості 0,75;

HashMap(int capacity, float loadFactor) - створює пустий обєкт з початковою ємністю capacity і

показником завaнтаженості loadFactor;

HashMap(Map f) - створює обєкт класу HashMap, що містить всі елементи відображення f, з ємністю, рівною подвоєному числу елементів відображення f, але не менше 11, і показником завантаженості 0,75.

112

Клас WeakHashMap відрізняється від класу HashMap тільки тим, що в його обєктах не використовувані елементи, на які ніхто не посилається, автоматично виключаються із обєкта.

6.18. Упорядковані відображення

Клас ТгееМар повністю реалізує інтерфейс sortedMap. Він реалізований як бінарне дерево пошуку, значить його елементи зберігаються в упорядкованому вигляді. Це значно прискорює пошук потрібного елемента. Порядок задається або природним слідуванням елементів, або обєктом, реалізуючим інтерфейс няння Comparator. В цьому класі чотири конструктори:

ТгееМар () — створює пустий обєкт з природним порядком елементів;

TreeМар (Comparator с) — створює пустий обєкт, в якому порядком елементів задається обєктом порівняння с;

ТгееМар (Map f) — створює обєкт, що містить всі елементи відображення f, з природним порядком його елементів;

ТгееМар (SortedMap sf) — створює обєкт, що містить всі елементи відображення sf в тому ж порядку.

Тут треба пояснити, яким способом можна задати упорядкованість елементів колекції

6.19. Порвіняння елементів колекцій

Інтерфейс Comparator описує два методи порівняння:

int compare(Object obj1, Оbject obj2) - повертає відємне число, якщо obj1 в певному змісті менше obj2; нуль, якщо вони вважаються рівними; додатне число, якщо obj1 більше obj2. Для студентів, знайомих з теорією множин, скажемо, що цей метод порівняння має властивості рефлексивності, антисиметричності і транзитивності;

boolean equals(Object obj) - порівнює даний обєкт з обєктом obj, повертає true, якщо обєкти співпадають в певному змісті, заданому цим методом.

Для кожної колекції можна реалізувати ці два методи, задавши конкретний спосіб порівняння елементів, і визначити обєкт класу SortedMap другим конструктором. Елементи колекції будуть автоматично відсортовані в заданому порядку. Лістинг 6.6 показує один из можливих способів упорядкованості комплексних чисел — обєктів класу Сomplex із лістингу 2.4. Тут описується клас ComplexCompare, реалізуючий інтерфейс Comparator. В лістинзі 6.7 він застосовується для упорядкованого зберігання множини комплексних чисел.

Лістинг 6.6. Порівняння комплексних чисел

import java.util.*;

class ComplexCompare implements Comparator{ public int compare(Object objl, Object obj2){ Complex z1 = (Complex)objl, z2 = (Complex)obj2; double re1 = z1.getRe(), iml = zl.getlm(); double re2 = z2.getRe(), im2 = z2.getlm();

if (rel != re2) return (int)(re1 - re2); else if (im1 != im2) return (int)(im1 — im2); else return 0;

}

public boolean equals(Object z) { return compare(this, z) == 0;

}

}

6.20. Класи, що створюють множини

Класс HashSet повністю реалізує інтерфейс set і ітератор типу iterator. Класс HashSet використовується в тих випадках, коли треба зберігати тільки одну копію кожного елемента. В класі HashSet чотири

113

конструктори:

HashSet () - створює пустий обєкт з показником завантаженості 0,75;

HashSet (int capacity) - створює пустий обєкт з початковою ємністю capacity і показником завнтаженості 0,75;

HashSet (int capacity, float loadFactor) — створює пустий обєкт з початковою ємністю capacity і

показником завaнтаженості loadFactor;

HashSet (Collection coll) — створює обєкт класу HashMap, що містить всі елементи відображення coll, з ємністю, рівною подвоєному числу елементів відображення f, але не менше 11, і показником завантаженості 0,75.

6.21. Упорядковані множини

Класс TreeSet повністю реалізує інтерфейс sortedSet і ітератор типу iterator. Клас TreeSet реалізований як бінарне дерево пошуку, значить, його елементи зберігаються в упорядкованому вигляді. Це значно прискорює пошук потрібного елемента. Порядок задається або природним слідуванням елементів, або обєктом, реалізуючим інтерфейс порівняння Comparator. Цей клас зручний при пошуку елемента в множині, наприклад, для перевірки, чи володіє якийсь елемент властивістю, що визначає множину. В класі TreeSet чотири конструктори:

TreeSet() - створює пустий обєкт з при родним порядком елементів;

TreeSet (Comparator с) - створює пустий обєкт, в якому порядок задається обєктом порівняння с;

TreeSet (Collection coll) - створює обєкт, що містить всі елементи колекції coll, з природним порядком її елементів;

TreeSet (SortedMap sf) - створює обєкт, що містить всі елементи відображення sf, в тому ж порядку.

Влістинзі 6.7 показано, як можна зберігати комплексні числа в упорядкованому вигляді. Порядок задається обєктом класу ComplexCompare, визначеного в лістинзі 6.6.

Лістинг 6.7. Зберігання комплексних чисел в упорядкованому вигляді

TreeSet ts = new TreeSet (new ComplexCompare()); ts.add(new Complex(1.2, 3.4));

ts. add (new Complex (-1.25, 33.4»; ts.add(new Complex(1.23, -3.45)); ts.add(new Complex(16.2, 23.4)); Iterator it = ts.iterator();

while(it.hasNext()) , ((Complex)it.next()).pr();

6.22. Дії з колекціями

Колекції призначені для зберігання елементів у зручному для подальшої обробки вигляді. Дуже часто обробка заключається в сортуванні елементів і пошуку потрібного елемента. Ці і інші методи обробки зібрані в класс Collections.

6.23. Методи класу Collections

Всі методи класу Сollections статичні, ними можна користуватися, не створюючи екземпляри класу Collections. Як звичайно в статичих методах, колекція, з якою працює метод, задається його аргументом. Сортування може бути зроблена лише в упорядкованій колекції, реалізуючій інтерфейс List. Для сортуванні в класі Сollections єсть два методи:

static void sort (List coll) - сортує в природному порядку зростання колекцію coll, реалізуючу інтерфейс List;

static void sort (List coll, Comparator c) - сортує колекцію coll в порядку, заданому обєктом с. Після сортування можна здійснювати бінарний пошук в колекції.

114

static int binarySearch(List coll, Object element) - відшукує елемент element у відсортованій в природному порядку зростання колекції coll і повертає індекс елемента або відємне число, якщо елемент не знайдено; відємне число показує індекс, з яким елемент element був би вставлений в колекцію, з протилежним знаком;

static int binarySearch(List coll, Object element, Comparator c) - те ж, але колекція відсортована в порядку, визначеному обєктом с.

Чотири методи знаходять найбільший і найменший елементи в упорядкованій колекції:

static object max (Collection coll) - повертає найбільший в природному порядку елемент колекції coll;

static Object max (Collection coll, Comparator c) - те ж в порядку, заданому обєктом с;

static object min (Collection coll) - повертає найменший в природному порядку елемент колекції coll;

static Object min(Collection coll, Comparator c) - те ж в порядку, заданому обєктом с.

Два методи "перемішують" елементи колекції випадковим способом:

static void shuffle (List coll) - випадкові числа задаються по замовчуванню;

static void shuffle (List coll, Random r) - випадкові числа визначаються обєктом r.

Метод reverse (List coll) змінює порядок розташування елементів на зворотний.

Метод copy (List from, List to) копіює колекцію from в колекцію to.

Метод fill (List coll, Оbject element) замінює всі елементи даної колекції coll елементом element.

Зрештою методів познайомимося по мірі необхідності.

6.24. Заключення

Таким чином, в даному уроці ми вияснили, що мова Java представляє багато засобів для роботи з великими обємами інформації. В більшості випадків достатньо додати в програму три-пять операторів, щоб можна було зробити нетривіальну обробку інформації.

В наступному уроці ми розглянемо аналогічні засоби для роботи з масивами, датами, для одержання випадкових чисел і інших необхідних засобів програмування.

Лабораторна робота 5. Використання класів Vector, Stack і HashTable для створення баз даних.

1.Користуючись класом Vector створіть базу даних, елементами якої є обєкти класу Student, створені на попередній роботі. Передбачити необхідні методи управління базою даних і проілюструвати їх на працюючій програмі.

2.Переробіть попередню програму з використанням класу Stack. Проілюструйте в програмі дію методів, відсутніх у класі Vector.

3.Переробіть програму пункту 1 з використанням класу HashTable використовуючи пари (Прізвище студента, обєкт класу Student).

115

Урок 7

Класи-утиліти

Робота с масивами

Локальні установки

Робота з датами і часом

Часовий пояс і літній час

Клас Сalendar

Підклас GregorianCalendar

Представлення дати і часу

Одержання випадкових чисел

Копіювання масивів

Взаємодія з системою

Вцьому уроці описані засоби, корисні для створення програм: робота с масивами, датами, випадковими числами.

7.1.Робота з масивами

Вкласі Arrays із пакету java.utiІ зібрано багато методів для роботи з масивами. Їх можна розділити на чотири групи.

Вісімнадцять статичних методів сортують масиви з різними типами числових елементів у порядку зростання чисел або просто обєкти в їх природному порядку. Вісім із них мають простий вигляд

static void sort(type[] a)

де type може бути один із семи примітивних типів byte, short, int, long, char, float, double або тип Object.

Вісім методів з тими ж типами сортують частину масиву від індексу from включно до індексу to виключно:

static void sort(type[] a, int from, int to)

Останні два методи сортування упорядковують масив або його частину з елементами типу Оbject по правилу, заданому обєктом с, реалізуючим інтерфейс Comparator:

static void sort(Object[] a, Comparator c)

static void sort(Object[] a, int from, int to, Comparator c)

Після сортування можна організувати бінарний пошук в масиві одним із девяти статичних методів пошуку. Вісім методів мають вигляд

static int binarySearch(type[] a, type element)

де type - один із тих же восьми типів. Девятий метод пошуку має вигляд

static int binarySearch(Object[] a, Object element, Comparator c).

Він відшукує елемент element в масиві, відсортованому в порядку, заданому обєктом с. Методи пошуку повертають індекс знайденого елемента масиву. Якщо елемент не знайдено, то повертається відємне число, що означає індекс, з яким елемент був би вставлений в масив у заданому порядку, з протилежним знаком.

Вісімнадцять статичних методів заповнюють масив або частину масиву указаним значенням value:

static void fill(type[], type value)

static void fill(type[], int from, int to, type value)

де type - один із восьми примітивних типів або тип Оbject. Нарешті, девять статичних логічних методів

116

порівнюють масиви:

static boolean equals(type[] al, type[] a2)

де type - один із восьми примітивних типів або тип Object.

Масиви вважаються рівними, і повертається true, якщо вони мають однакову довжину і рівні елементи масивів з однаковими індексами. В лістинзі 7.1 приведений простий приклад роботи з цими методами.

Лістинг 7.1. Застосування методів класу Arrays

import java.util.*; class ArraysTest{

public static void main(String[] args){

int[] a = {34, -45, 12, 67, -24, 45, 36, -56}; Arrays.sort(a) ;

for (int i = 0; i < a.length; i++) System.out.print (a[i] + " "); System.out.println();

Arrays.fill(a, Arrays.binarySearch(a, 12), a.length, 0); for (int i = 6; i < a.length; i++)

System.out.print(a[i] + " "); System.out.println();

}

}

7.2. Локальні установки

Деякі дані — дати, час — традиційно представляються в різних місцевостях по-різному. Наприклад, дата в Росії виводится в форматі число, місяць, рік через точку: 27.06.01. В США прийнято запис місяць/число/рік через похилу риску: 06/27/01. Сукупність таких форматів для даної місцевості, як говорять на жаргоні "локаль", зберігається в обєкті класу Locale із пакету java.utiІ. Для створення такого обєкта достатньо знать мову language і місцевість country. Інколи потрібна третя характеристика — варіант variant, що визначає програмний продукт, наприклад, "WIN", "MAC", "POSIX". По замовчуванню місцеві установки визначаються операційною системою і читаються із системних властивостей. Подивіться на рядки :

user.language = ua// Мова — українська user.region = UA // Місцевість — Україна

file.encoding = Cp1251 // Байтове кодування — CP1251

Вони визначають українську локаль і локальне кодування байтових символів. Локаль, установлену по замовчуванні на тій машині, де виконується програма, можна вияснити статичним методом Locale.getDefault(). Щоб працювати з другою локаллю, її треба спочатку створити. Для цього в класі Locale єсть два конструктори:

Locale(String language, String country)

Locale(String language, String country. String variant)

117

Параметр language — це рядок із двух літер, визначений стандартом ISO639, наприклад, "ru", "fr", "en". Параметр country — рядок із двох заглавних літер, визначений стандартом ISO3166, наприклад, "RU", "US", "EN". Параметр variant не визначається стандартом, це може бути, наприклад, рядок "Traditional". Локаль часто указують одним рядком "ru_RU", "en_GB", "en_US", "en_CA" і т. д. Після створення локалі можна зробити її локаллю по замовчуванню статичним методом:

Locale.setDefault(Locale newLocale);

Декілька статичних методів класу Locale дозволяють одержати параметри локалі по замовчуванні або локалі, заданої параметром locale:

String getСountry() - стандартний код країни із двох літер;

String getDispІayCountry() - країна записується словом, що може бути виведене на екран; String getDisplayCountry (Locale locale) - те ж для указаної локалі.

Такі ж методи єсть для мови і варіанта. Можна продивитись список всіх локалів, визначених для даної JVM, і їх параметрів, що виводиться в стандартному вигляді:

Locale[] getAvailableLocales()

String[] getlSOCountries()

String[] getlSOLanguages()

Установленна локаль надалі використовується при виведенні даних в місцевому форматі.

7.3. Робота з датами і часом

Методи роботи з датами часом зібрані в два класи: Calendar і Date із пакету java.utiІ. Обєкт класу Date зберігає число мілісекунд, що пройшло з 1 січня 1970 г. 00:00:00 по Грінвічу. Це "день народження" UNIX, він називається "Epoch". Клас Date зручно використовувати для відрахунку проміжків часу в мілісекундах. Одержати поточне число мілісекунд, що пройшли з моменту Epoch на тій машині, де виконується програма, можна статичним методом

System.currentTimeMillis()

В класі Date два конструктори. Конструктор Date() заносить в створюваний обєкт поточний час машини, на якій виконується програма, по системному годиннику, а конструктор Date(long miІІisec) — указане число. Одержати значення, що зберігається в обєкті, можна методом long getTime(), установити нове значення - методом setTime(long newTime). Три логічних методи порівнюють час:

boolean after (long when) - повертає true, якщо час when більше даного;

boolean before (long when) - повертає true, якщо when менше даного;

boolean after (Object when) - повертає true, якщо when - обєкт класу Date і часи співпадають.

Ще два методи, порівнюючи час, повертають відємне число типу int, якщо даний час менше аргумента when; нуль, якщо часи співпадають; додатне число, якщо даний час більше аргумента when:

int compareTo(Date when);

int compareTo(Оbject when) — якщо when не відноситься до обєктів класу Date, створюється виключна ситуація.

Перетворення мілісекунд, що зберігаються в обєктах класу Date, в поточні час і дату виконується методами класу calendar.

7.3.1. Часовий пояс і літній час

Методи установки і зміни часового поясу (time zone), а також літнього часу DST (Daylight Savings Time), зібрані в абстрактному класі Timezone із пакету java.utiІ. В цьому ж пакеті єсть його реалізація — підкласс SimpleTimeZone. В класі SimpleTimeZone три конструктори, але частіше всього обєкт створюється статичним методом getDefault(), що повертає часовий пояс, установлений на машині, яка виконує

118

програму. В цих класах багато методів роботи з часовими поясами, але в більшоті випадків вимагається тільки узнати часовий пояс на машині, що виконує программу, статичним методом getDefault(), перевірити, чи здійснюється перехід на літній час, логічним методом useDaylightTime(), і установити часовий пояс методом setDefault (TimeZone zone).

7.3.2. Клас Calendar

Класс Calendar — абстрактний, в ньому зібрані загальні властивості календарів: юліанського, григоріанського, місячного. В Java API поки що єсть тільки одна його реалізація — підклас GregorianCalendar. Оскільки Сalendar — абстрактний клас, його екземпляри створюються чотирма статичними методами по заданій локалі і/або часовому поясі:

Calendar getlnstance()

Calendar getlnstance(Locale loc)

Calendar getlnstance(TimeZone tz)

Calendar getlnstance(TimeZone tz, Locale loc)

Для роботи з місяцями визначені цілочисельні константи від JANUARY до DECEMBER, а для роботи з днями тижня — константи від MONDAY до SUNDAY. Перший день тижня можна узнати методом int getFirstDayOfWeek(), a установити — методом setFirstDayOfWeek(int day), наприклад:

setFirstDayOfWeek(Calendar.MONDAY)

Решта методів дозволяють проглянути часі часовий пояс або установити їх.

7.3.3. Підклас GregorianCalendar

В григоріанському календарі дві цілочисельні константи визначають ери: вс (before Christ) і AD (Anno Domini). Сім конструкторів визначають календар по часу, часовому поясу і/або локалі:

GregorianCalendar()

GregorianCalendar(int year, int month, int date)

GregorianCalendar(int year, int month, int date, int hour, int minute)

GregorianCalendar(int year, int month, int date, int hour, int minute, int second)

GregorianCalendar(Locale loc)

GregorianCalendar(TimeZone tz)

GregorianCalendar(TimeZone tz, Locale loc)

Після створення обєкта треба визначити дату переходу з юліанського календаря на григоріанський календар методом setGregorianChange(Date date). По замовчуванню це 15 жовтня 1582 г. На території Росії перехід був здійснений 14 лютого 1918 р., значить, створення обєкта greg треба виконати так:

GregorianCalendar greg = new GregorianCalendar();

greg.setGregorianChange(new GregorianCalendar(1918, Calendar.FEBRUARY, 14) .getTime ()) ;

Узнати, чи являється рік високосним в григоріанському календарі, можна логічним методом isLeapYear(). Метод get(int field) повертає елемент календаря, заданий аргументом field. Для цього аргумента в класі Calendar визначені наступні статичні цілочисельні константи: ERA, WEEK_OF_YEAR, DAY_OF_WEEK, SECOND, YEAR, WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, MILLISECOND, MONTH, DAY_OF_YEAR, HOUR_OF_DAY, ZONE_OFFSET, DATE, DAY_OF_MONTH, MINUTE, DST_OFFSET..

Декілька методів set(), що використовують ці константи, устанавлюють відповідні значення.

7.3.4. Представлення дати і часу

Різноманітні способи представлення дат і часу можназдійснювати методами, зібраними в абстрактний клас DateFormat і його підклас SimpleDateFormat із пакету Java.text. Клас DateFormat пропонує чотири стилі представлення дати і часу:

стиль SHORT представляє дату і час в короткому числовому вигляді: 27.04.01 17:32; в локалі

119

США: 4/27/01 5:32 РМ;

стиль MEDIUM задає рік чотирма цифрами і показує секунди: 27.04.2001 17:32:45; в локалі США місяць представляється трьома буквами;

стиль LONG представляє місяць словом і додає часовий пояс: 27 квітень 2001 р. 17:32:45 GMT+03.-00;

стиль FULL в російській локалі такий же, як і стиль LONG; в локалі США додається ще день тижня.

Єсть ще стиль DEFAULT, співпадаючий зі стилем MEDIUM.

При створенні обєкта классу SimpІeDateFormat можна задати в конструкторі шаблон, що визначає якийсь інший формат, наприклад:

SimpІeDateFormat sdf = new SimpІeDateFormat("dd-MM-yyyy hh.iran");

System.out.println(sdf.format(new Date()));

Одержимо виведення в такому вигляді: 27-04-2001 17.32.

В шаблоні літера d означає цифру дня місяця, м — цифру місяця, у — цифру року, h — цифру години, m

— цифру хвилин. Решта позначень для шаблону указані в документації по классу SimpІeDateFormat. Ці буквенні позначення можна змінити за допомогою класу DateFormatSymbols. Не у всіх локалях можна створити обєкт класу SimpІeDateFormat. В таких випадках використовуються статичні методи getІnstance() класу DateFormat, що повертає обєкт класу DateFormat. Параметрами цих методів служать стиль представлення дати і часу і, може бути, локаль. Після створення обєкта метод format() класу DateFormat повертає рядок з датою і часом, згідно заданому стилю. В якості аргумента задається обєкт класу Date. Наприклад:

System.out.println("LONG: " + DateFormat.getDateTimelnstance(

DateFormat. LONG, DateFormat. LONG) . format (new Date ()));

або

System.out.println("FULL: " + DateFormat.getDateTimelnstance(

DateFormat.FULL,DateFormat.FULL, Locale.US).format(new Date()));

7.4. Одержання випадкових чисел

Одержати випадкове невідємне число, строго менше одиниці, типу double можна статичним методом random() із класу java.lang.Math. При першому зверненні до цього методу створюється генератор псевдовипадкових чисел, якийй використовується потім при одержанні наступних випадкових чисел. Більш серйозні дії з випадковими числами можна організувати за допомогою методів класу Random із пакету java.utiІ. В класі два конструктори:

Random (long seed) — створює генератор псевдовипадкових чисел, що використовує для початку роботи число seed;

Random() —вибирає в якості початкового значення поточний час.

Створивши генератор, можна одержувати випадкові числа відповідного типу методами nextBoolean(), nextDouble(), nextFloat(), nextGaussian(), next int(), nextLong(), nextІnt(int max) або записати зразу послідовність випадкових чисел в заздалегідь визначений масив байтів bytes методом nextBytes(byte[] bytes). Дійсні випадкові числа рівномірно розподіляються в діапазоні від 0,0 включно до 1,0 виключно. Цілі випадкові числа рівномірно розподіляються по всьому діапазону відповідного типу за одним виключенням: якщо в аргументі указано цле число max, то діапазон випадкових чисел буде від нуля включно до max виключно.

7.5. Копіювання масивів

В класі System із пакету java.lang єсть статичний метод копіювання масивів, який використовує сама виконуюча система Java. Цей метод діє швидкоо і надійно, його зручно застосовувати в програмах. Синтаксис:

120

static void arraycopy(Object src, int src_ind, Object dest, int dest_ind, int count)

Із масиву, на який указує посилка src, копіюється count елементів, починаючи з елемента з індексом src_ind, в масив, на якийй указує посилка dest, починаючи з його елемента з індексом dest_ind. Всі індекси повинні бутиь задані так, щоб елементи лежали в масивах, типи масивів повинні бути сумісними, а примітивні типи зобовязані повністю співпадати. Посилки на масив не повинні бутиь рівні null. Посилки src і dest можуть співпадати, при цьому для копіювання створюється проміжний буфер. Метод можна використовувати, наприклад, для зсуву елементів в масиві. Після виконання

int[] arr = {5, 6, 1, 8, 9, 1, 2, 3, 4, 5, -3, -7}; System.arraycopy(arr, 2, arr, 1, arr.length - 2);

одержимо (5, 7, 8, 9, 1, 2, 3, 4, 5, -3, -7, -7}.

7.6. Взаємодія з системою

Клас System дозволяє здійснювати і деяку взаємодію з системою під час виконання програми (run time). Але крім нього для цього єсть спеціальний клас Runtime. Клас Runtime містить деякі методи взаємодії з JVM під час виконання програми. Кожний додаток може одержати тільки один екземпляр даного класу статичним методом getRuntime (). Всі виклики цього методу повертають посилку на один і той же обєкт.

Методи fгееМемогу() і totaІMemory() повертають обєм вільної і всієї памяті, що знаходиться в розпорядженні JVM для розміщення обєктів, в байтах, у вигляді числа типу long. He варто твердо спиратися на ці числа, оскільки обєм памяті змінюється динамічно.

Метод exit(int status) запускає процес останова JVM і передає операційній системі статус завершення status. По домовленості, ненульовий статус означає ненормальне завершення. Зручніше використовувати аналогічний метод класу system, який являється статичним.

Метод halt(int status) здійснює негайний останов JVM. Він не завершує запущені процеси нормально і повинен використовуватися лише в аварійних ситуаціях.

Метод loadІibrary(string libName) дозволє підвантажити динамічну бібліотеку під час виконання по її імені libName.

Метод load (string fileName) підвантажити динамічну бібліотеку по імені файла fileName, в якому вона зберігається. Взагалі ж, замість цих методів зручніше використовувати статичні методи класу system з тими ж іменами і аргументами.

Метод gc() запускає процес звільнення непотрібної оперативної памяті (garbage collection). Цей процес періодично запускається самою віртуальною машиною Java і виконується на фоні с невеликим пріоритетом, але можна його запустити і із програми. Знову-таки зручніше використовувати статичний Метод System.gc().

Нарешті, декілька методів ехес() запускають в окремих процесах виконувані файли. Аргументом цих методів служить командний рядок виконуваного файла. Наприклад, Runtime.getRuntime().exec ("notepad") запускає програму Блокнот на платформі MS Windows.

Методи exec() повертають екземпляр класу process, що дозволяють керувати запущеним процесом. Методом destroy() можна зупинити процес, методом exitValue() одержати його код завершення.

Метод waitFor() призупиняє основний підпроцес до тих пір, поки не закінчиться запущений процес.

Три методи getlnputStream(), getOutputStream() і getErrorStream() повертають вхідний, вихідний потік и потік помилок запущеного процесу (дивись урок 18).