Pозділ 2 теоретичні відомості мови програмування java 4 страница
Абстракція даних – введення типів даних, визначених користувачем і відмінних від базових. Ця концепція полягає у можливості визначати нові типи даних, з якими можна працювати так само, як і з основними типами даних. Крім того, абстракція має місце і при застосуванні шаблонів, тобто введенні абстрактних типів даних, які в залежності від умов їх застосування приймають той або інший тип.
Інкапсуляція – це механізм, який пов’язує код з даними, що ним обробляються, та зберігає їх як від зовнішнього впливу, так і від помилкового використання. Інкапсуляцію можна уявити як захисну оболонку, яка запобігає доступу до коду та даних з іншого коду, що знаходиться зовні цієї оболонки. Доступ до коду та даних в середині оболонки відбувається через чітко визначений інтерфейс. Потужність такого підходу полягає у тому, що кожен знає, як отримати доступ до інкапсульованого коду, і може користуватися ним незалежно від деталей його реалізації та без побоювання несподіваних наслідків.
Основою абстракціі та інкапсуляції в Java є клас. Клас визначає структуру та поведінку (дані і код) деякого набору об’єктів. Кожен об’єкт заданого класу містить як структуру (дані), так і поведінку, що визначається класом (так, як би ці об’єкти було проштамповано шаблоном у формі класу). Тому об’єкт іноді ще називають екземпляром класу. Таким чином, клас – це логічна конструкція, а об’єкт – це фізична реальність.
При створенні класу необхідно специфікувати код і дані, що складають цей клас. Разом всі ці елементи називають членами (members) класу. Дані, що визначаються в класі, називають змінними-членами (member variables), або полями класу. Код, який оперує з цими даними (тобто функції, що знаходяться в середині класу), називають методами-членами (member methods), або просто методами. В правильно записаних Java-програмах методи визначають, як можна використовувати змінні-члени. Отже, поведінку та інтерфейс класу визначають методи, що оперують з даними його екземплярів.
Оскільки мета створення класу – це інкапсуляція складності, існують механізми приховування її реалізації в середині класу. Методи і поля класу можуть бути помічені як private (приватний, локальний) або public (загальний). Модифікатор public вказує на все, що потрібно знати зовнішнім користувачам класу. Методи та поля з модифікатором private є доступними лише для методів даного класу. Будь-який код, що не є членом даного класу, не має доступу до private-методів і полів. Оскільки private-члени класу є доступними для інших частин програми тільки через public-методи класу, можна бути впевненим, що ніякі непотрібні дії не виконуються.
Успадкування (наслідування) – це процес, за допомогою якого один об’єкт отримує властивості іншого об’єкта. Воно важливе, тому що підтримує концепцію ієрархічної класифікації. Переважною частиною знань можна управляти лише за допомогою ієрархічних (тобто організованих “згори донизу”) класифікацій. Без застосування класифікацій кожен об’єкт потребував би явного визначення всіх своїх характеристик. Завдяки використанню успадкування об’єкт потребує визначення лише тих якостей, які роблять його унікальним у власному класі. Тому саме механізм успадкування дає можливість одному об’єкту бути специфічним екземпляром загального випадку.
У навколишньому світі ми бачимо об’єкти, пов’язані між собою ієрархічно, наприклад, тварини, ссавці, собаки. Якщо ми хочемо описати тварини абстрактним чином, нам необхідно визначити деякі їх атрибути, наприклад, розмір, вага, стать, вік тощо. Тваринам також притаманна певна поведінка – вони їдять, дихають, сплять. Такий опис атрибутів і поведінки і визначає клас тварин.
Якщо ми захочемо описати більш специфічний клас тварин, такий як ссавці, вони повинні були б мати більш специфічні атрибути, такі як тип зубів і молочні залози. Такий клас відомий як підклас тварин, тоді як клас тварин називають суперкласом (батьківським класом, класом-пращуром).
Оскільки ссавці – це більш точно специфіковані тварини, то говорять, що вони успадковують всі атрибути тварин. Підклас, що знаходиться на більш глибокому рівні ієрархії, успадковує всі атрибути кожного свого батьківського класу в ієрархії класів.
Успадкування щільно пов’язане з інкапсуляцією. Якщо даний клас інкапсулює деякі атрибути, то будь-який підклас буде мати ті ж самі атрибути плюс атрибути, які він додає як частину своєї спеціалізації. Це ключова концепція, яка дозволяє об’єктно-орієнтованим програмам зростати за складністю в арифметичній, а не геометричній прогресії. Новий підклас успадковує всі атрибути всіх своїх батьків. Він не має не передбачуваних зв’язків з рештою коду в програмі.
Крім того, у похідному класі успадковані функції можуть бути перевизначені. Таким чином будують ієрархії класів, пов’язаних між собою. Якщо об’єкт наслідує свої атрибути від одного базового класу, це буде просте успадкування. Якщо об’єкт успадковує атрибути від кількох батьків, це буде множинне успадкування. Але у мові Java множинне успадкування у безпосередньому вигляді не існує, його механізм є дещо специфічним.
Поліморфізм (грецькою ”polymorphos” – множинність форм) – властивість, яка дозволяє використовувати один інтерфейс для спільного класу дій. Специфічна дія точно визначається в залежності від конкретної ситуації. Наприклад, розглянемо стек (список типу LIFO – Last-In, First-Out; останнім увійшов, першим вийшов). Програма може потребувати три типи стеків. Один стек використовується для цілих чисел, другий – для чисел з плаваючою крапкою, третій – для символів. Алгоритм, який реалізує кожен стек, один і той самий, хоча дані, що зберігаються, різні. Не об’єктно-орієнтована мова вимагала б створення трьох різних стекових підпрограм, кожна з яких мала б своє власне ім’я. Завдяки поліморфізму в мові Java можна визначити спільний для всіх типів даних набір стекових підпрограм, що використовують одне і те саме ім’я.
Взагалі суть концепції поліморфізму можна виразити фразою “один інтерфейс, багато методів”. Це означає, що можна спроектувати спільний інтерфейс для групи пов’язаних родинними зв’язками об’єктів. Це дозволяє зменшити складність, припускаючи використання одного й того самого інтерфейса для загального класу дій. Задача компілятора – обрати специфічну дію (тобто метод) для його використання в кожній конкретній ситуації. Програміст не повинен робити це “вручну”. Йому необхідно тільки пам’ятати та використовувати спільний інтерфейс.
Отже, поліморфізм – це властивість програмного коду поводитись по-різному в залежності від ситуації, що виникає в момент виконання.
Якщо провести аналогію з собакою, можна сказати, що нюх у собаки поліморфний. Якщо він чує кильку, то гавкає та біжить за нею. Якщо чує їжу, виділяє слину та біжить до миски. В обох ситуаціях працює одне й те саме почуття – нюх. Різниця полягає в тому, що саме він нюхає, тобто в типі даних, з якими оперує ніс собаки. Ту ж спільна концепцію реалізовано в мові Java відносно методів у Java-програмах.
При правильному застосуванні наведені принципи ООП – абстракція, інкапсуляція, поліморфізм та успадкування – взаємодіють таким чином, щоб створити деяке середовище програмування, яке має забезпечити більш стійкі та масштабовані програми порівняно з моделлю, орієнтованою на процеси. Вдало спроектована ієрархія класів є базисом повторного використання коду, для створення та тестування якого було витрачено чимало часу та зусиль. Інкапсуляція дозволяє реалізаціям подорожувати в часі без руйнування коду, доступ до якого здійснюється з допомогою public-інтерфейса класів. Поліморфізм дозволяє створювати ясний та читабельний код.
Мова Java – це об’єктно-орієнтована мова програмування, що веде свою історію від відомої мови C++. Але, на відміну від останньої, Java є мовою, що інтерпретується. Програми, написані на ній, здатні працювати в різних місцях мережі і не залежать від платформи, на якій виконуються написані на ній додатки. Java свідомо уникає арифметики з покажчиками й іншими ненадійними елементами, якими буяє C++, тому, розробляючи на ній додатки, ми позбавляємося багатьох проблем, звичайних при створенні програмного забезпечення.
Для відлагодження програм мовою Java підійде будь-який з пакетів: Microsoft Visual J++, Symantec Cafe, Java Add-On зі складу Borland C++ 5.0 чи Sun Java WorkShop. Якщо є бажання користуватися командними файлами, то можна завантажити з Web-сервера http://java.sun.com "рідний" варіант компілятора Java компанії Sun – Java Development Kit (JDK).
У термінах мови Java маленький додаток, що вбудовується в сторінку Web, називається аплетом. Власне кажучи, створення аплетів – основне застосування для Java. Аплети здобули собі звання справжніх прикрас для Web. Аплет може бути і вікном анімації, і електронною таблицею, і усім, що тільки можна собі уявити. Але це не означає, що на Java не можна писати нормальні додатки з вікнами. Ця мова програмування споконвічно була створена для звичайних додатків, що виконуються в Internet і в інтрамережах, і вже потім стала використовуватися для виготовлення аплетів.
Елементарні будівельні блоки в Java називаються класами (як і в C++). Клас складається з даних і коду для роботи з ними. У засобах для розробки мовою Java усі стандартні класи, доступні програмісту, об'єднані для зручності в пакети – ще одні елементарні блоки Java-програм.
От найпростіша програма, що наводиться в багатьох підручниках по Java:
class Hello
{
public static void main(String args[])
{
System.out.println("Hello, World!");
}
}
На рисунку 2.1 схематично представлено основні етапи створення додатку за допомогою стандартних засобів JDK. Запустимо компілятор Java з назвою javac і отримаємо готовий клас Java – Hello.class:
javaс Hello.java
Компілятор javac генерує окремий файл для кожного класу, визначеного у файлі вихідного тексту, незалежно від кількості файлів вихідного тексту.
Початковий файл Hello.java |
Файл байт-кодів Hello.class |
Підготовка початкового коду програми, редагування |
Компіляція (javac.exe) |
Виконання (java.exe) |
Рисунок 2.1 – Редагування, компіляція та запуск на виконання Java-програми |
Якщо хочемо подивитися, як цей додаток працює, виконаємо його за допомогою команди «java Hello».
При цьому необхідно набрати ім'я класу, що запускається, точно так, як воно написано у вихідному тексті програми, тобто з дотриманням регістра, інакше ви одержите повідомлення про помилку.
Розглянемо поелементно вихідний текст нашого прикладу. Вся програма складається з одного класу з ім'ям Hello. У цьому класі є єдиний метод main(), аналогічний функції main() у мовах програмування C і C++, який і визначає місце, з якого програма починає виконуватися (так звана точка входу). Модифікатор доступу public перед ім'ям методу main() вказує на те, що цей метод доступний усім класам, що бажають його викликати, незалежно від прав доступу і від місця їхнього розташування. Модифікатор static говорить про те, що для всіх екземплярів класу Hello і в наслідуваних від нього класах існує лише один метод main(), поділюваний між усіма класами, що, можливо, будуть успадковані від Hello. Це допомагає уникнути появи безлічі точок входу в програму, що викликає помилку.
Через змінну-масив args типу String (рядок) передаються параметри командного рядка класу. У Java перший елемент списку параметрів відповідає першому параметру, а не імені програми, що запускається, як це прийнято в мовах C і C++. Доступ до нього можна здійснити через вираз args. Рядок System.out.println ("Hello, World!") посилає рядок тексту в стандартний потік виведення, тобто на екран. Ми відправляємо повідомлення стандартному класу System, що відповідає за основні системно-незалежні операції, наприклад, виведення тексту на консоль. А вже з цього класу ми викликаємо клас стандартного потоку виведення. Слідом йде виклик методу println(), що, власне, і відображає рядок тексту на екрані монітора, по завершенню чого переводить курсор на наступний рядок.
У Java всі методи класу описуються тільки в середині цього класу. Таким чином, відпадає необхідність у пересуванні по тексту в пошуку методів класів.
Якщо засвоїти вміст пакету Java з ім'ям java.awt, що розшифровується як Abstract Windowing Toolkit (Набір абстрактної роботи з віконною системою), то відкриються незлічимі можливості по створенню інтерфейсів і віконної графіки. Цей пакет забезпечує машинно-незалежний інтерфейс керування віконною системою будь-якої віконної операційної системи. До складу java.awt входять більше 40 класів, що відповідають за елементи графічного середовища користувача (GUI). В основному awt застосовується при написанні аплетів для сторінок Web. При перегляді сторінки на Web-сервері аплет передається на машину користувача, де і запускається на виконання.
Тепер ми можемо розглянути аплет, що робить те саме, що і вже розглянутий раніше приклад, тобто виводить рядок на екран:
import java.awt.*;
public class Hello extends java.applet.Applet
{
public void init() {}
public void paint(Graphics g)
{
g.drawString("Hello, Java!",20,30);
}
}
Першим рядком в аплет включаються всі необхідні класи з пакету java.awt, про який ми тільки що говорили. Ключове слово import має приблизно те ж значення, що й оператор #include мов C і C++. Далі слідує опис класу нашого аплета, якому передує модифікатор доступу public. Його задача – дати можливість використовувати наш клас ззовні, тобто запускати його з зовнішніх програм. Якщо цього слова не буде, компілятор видасть повідомлення про помилку, указавши, що аплету потрібно опис інтерфейсу доступу. Далі йде ключове слово extends і назва класу. Так у Java позначається процес успадкування. Цим словом ми вказуємо компілятору успадкувати (розширити) стандартний клас java.applet.Applet, відповідальний за створення і роботу аплета. Метод init() викликається в процесі ініціалізації аплета. Зараз цей метод порожній, але згодом, можливо, ми скористаємося ним для своїх цілей. За відображення рядка відповідає інший метод – paint(). Він викликається в той момент, коли потрібно перемалювати дані на екрані. Тут за допомогою методу drawString() стандартного класу Graphics малюється рядок "Hello, Java!" з екранними координатами (20, 30).
Опишемо базові типи даних. Ідентифікатори мови Java повинні починатися з букви будь-якого регістра або символів "_" і "$". Далі можуть йти і цифри. Наприклад, _Java - правильний ідентифікатор, а 1_$ - ні. Ще одне обмеження Java виникає з його властивості використовувати для збереження символів кодування Unicode, тобто можна застосовувати тільки символи, що мають порядковий номер більш 0x0 у розкладці символів Unicode.
Коментарі. У стандарті мови Java існує три типи коментарів:
/*Comment*/
//Comment
/** Comment*/
Перші два являють собою звичайні коментарі, застосовувані як у Java, так і в C++. Останній – особливість Java, введена в цю мову для автоматичного документування. Після написання вихідного тексту утиліта автоматичної генерації документації збирає тексти таких коментарів в один файл.
Цифрові літерали схожі з аналогічними в мові C++. Правила для цілих чисел прості:
- якщо в цифри немає суфікса і префікса, то це десяткове число;
- у вісімкових числах перед цифрою стоїть нуль;
- для шістнадцяткових чисел префікс складається з нуля і букви X (0x чи 0X).
- при додаванні до цифри букви L числу присвоюється тип long (довге ціле).
Приклади: 23 (десяткове),
0675 (вісімкове),
0x9FA (шістнадцяткове),
456L (довге ціле).
Числа із плаваючою крапкою. Для них передбачено два види описів:
- звичайне й
- експонентне.
При звичайному описі числа з плаваючою крапкою записуються в такій же формі, як і ті числа, що ми пишемо на папері від руки: 3.14, 2.73 і т.д. Це ж стосується і експонентного формату: 2.67E4, 5.0E-10. При додаванні суфіксів D і F виходять числа типів double і float. Наприклад, 2.71D і 0.981F.
Цілочисельні типи. У мові Java з'явився новий 8-бітний тип byte. Тип int, на відміну від аналогічного в C++, має довжину 32 біти. А для 16-бітних чисел передбачений тип short. У відповідності з усіма цими змінами тип long збільшився, ставши 64-бітним.
Чисельні типи даних наведено в таблиці 1:
Таблиця 2.1
Чисельні типи даних
Тип | Форма представлення | Значення за замовчуванням | Довжина (в бітах) | Максимальне значення |
byte | Ціле число зі знаком | |||
short | Ціле число зі знаком | |||
int | Ціле число зі знаком | |||
long | Ціле число зі знаком | порядку 1018 | ||
float | Число з плаваючою точкою | порядку 1038 | ||
double | Число з плаваючою точкою | порядку 10308 |
У стандарт Java був введений тип boolean, якого так довго чекали програмісти, що використовують C++. Він може приймати лише два значення: true і false.
У порівнянні з C++ масиви Java перетерпіли значні зміни. По-перше, змінилися правила їхнього опису. Масив тепер може бути описаний двома такими способами:
type name[];
type[] name;
При цьому масив не створюється, а лише описується. Отже, для резервування місця під його елементи треба скористатися динамічним виділенням за допомогою ключового слова new, наприклад:
char[] arrayName;
arrayName[] = new char[100];
або сполучити опис масиву з виділенням під нього пам'яті:
char array[] = new char[100];
Багатомірних масивів у Java немає, тому доводиться вдаватися до хитрощів. Наприклад, створити багатомірний масив можна як масив масивів:
float matrix[][] = new float[5][5];
Класи:
Говорячи про класи, необхідно ще раз пригадати один з трьох основних принципів ООП – успадкування. Використовуючи його, можна створити головний клас, який визначає властивості, спільні для набору елементів. Надалі цей клас може бути успадкований іншими, більш специфічними класами. Кожен з них додає ті властивості, які є унікальними для нього. В термінології Java клас, який успадковується, називається суперкласом (superclass). Клас, який виконує успадкування, називається підкласом (subclass). Тому підклас – це спеціалізована версія суперкласу. Він успадковує всі поля та методи суперкласу, та додає до них свої власні унікальні елементи. Щоб успадкувати клас, необхідно просто ввести визначення одного класу в інше, використовуючи ключове слово extends.
Розглянемо тепер, як описуються основні базові будівельні блоки мови Java – класи. Схема синтаксису опису класу така:
[Модифікатори] class Ім’яКласу [extends Ім’яСуперкласу]
[implements ІменаІнтерфейсів]
{
Дані класу;
Методи;
}
де Модифікатори – ключові слова типу public і т.д., що модифікують поведінку класу за замовчуванням;
Ім’яКласу – ім'я, що ви привласнюєте класу;
Ім’яСуперкласу – ім'я класу, від якого успадковується ваш клас;
ІменаІнтерфейсів – імена інтерфейсів, що реалізуються даним класом (про це в наступному розділі).
Типовий приклад класу ми вже наводили раніше. Це клас аплета, що виводить рядок на екран.
Модифікатори доступу визначають способи подальшого використання класу. При розробці самого класу вони не мають особливого значення, але вони дуже важливі при створенні інших класів або інтерфейсів на базі даного класу.
Модифікаторів доступу є три плюс ще один за замовчуванням.
public – класи public доступні для всіх об’єктів незалежно від пакета, тобто повністю не захищені. public-класи мають знаходитися в файлах з іменами, що збігаються з іменами класів.
friendly – значення за замовчуванням (тобто слово friendly в описі класу ніколи не пишеться!). friendly-класи доступні лише для об’єктів, що знаходяться в тому ж самому пакеті, що і даний клас, незалежно від того, чи є вони нащадками даного класу.
final-класи не можуть мати підкласів-нащадків. Тим самим ми втрачаємо одну з головних переваг ООП. Але іноді треба заборонити іншим класам змінювати поведінку розроблюваного класу (наприклад, якщо даний клас буде використаний як стандарт для обслуговування мережних комунікацій).
abstract – це клас, в якому є хоча б один абстрактний метод, тобто метод, для якого описаний лише заголовок (прототип функції), а саме тіло методу відсутнє. Зрозуміло, що реалізацію цього відсутнього методу покладено на класи-нащадки. Наприклад, створюється деякий клас для перевірки орфографії. Замість того, щоб закладати в нього перевірку української, російської, англійської орфографії, створюючи методи ukraineCheck(), russianCheck() і т. д. можна просто створити абстрактний метод grammarCheck(), перекладаючи роботу щодо перевірки конкретної граматики на класи-нащадки (які, можливо, будуть створені іншими фахівцями).
Можливість створення класів-нащадків – одна з головних переваг ООП. Для того, щоб використати вже існуючий клас слід указати в об’яві класу слово extends (розширює). Наприклад,
public class MyClass extends Frame.
В основі ієрархії в java знаходиться клас Object. Тому якщо навіть не використовується слово extends в описі класу, то створюється нащадок класу Object.
Нагадаємо, що клас-нащадок успадковує всі дані та методи суперкласу. В мові java відсутнє множинне успадкування (але є інтерфейси, які з успіхом замінюють його).
Чому в Java немає множинного успадкування? Це не випадково, тут спостерігається певна система. В мові Java розробники вирішили позбавитись від всього, що могло викликати проблеми в C++, наприклад, покажчики, множинна спадковість.
Конструктори. Створення екземплярів класу:
Конструктор – це метод класу, що має особливе призначення. Зокрема він використовується для установки деяких параметрів (наприклад, ініціалізації змінних) та виконання певних функцій (наприклад, виділення пам’яті).
Конструктор має те ж саме ім’я, що і клас. Наприклад,
MyClass(String name) {myName=name;}
Як відрізнити – це клас чи конструктор?
MyClass MyClass()
Так само, як в C++, один клас може мати декілька конструкторів. У цьому випадку вони мають відрізнятися за своїми параметрами. Також в описі конструктору можна використовувати модифікатори доступу, але не всі. Найчастіше конструктори роблять public.
Щоб використати розроблений клас, треба створити екземпляр класу, тобто об’єкт, що має тип даного класу. Створимо екземпляр класу MyClass:
MyClass myClass1= new MyClass();
Екземпляр класу може бути полем іншого класу. Так утворюється ієрархія за складом (спадковість реалізує ієрархію за номенклатурою).
public class Checker
{
MyClass myClass1= new MyClass();
int a=5;
. . .
}
Різниця між об’явою базового типу (наприклад, int) та створенням об’єкта – використання ключового слова new. При цьому відбувається:
1) виділення пам’яті під об’єкт;
2) виклик конструктора;
3) повернення посилання на об’єкт і присвоюється змінній myClass1.
Тому не зовсім коректно говорити, що конструктор нічого не повертає – він повертає посилання на об’єкт. Правильно – в описі конструктора відсутній тип даних, що повертається.
У чому полягає відмінність об’єктів від змінних базових типів? До базових типів завжди звертаються за значенням. До об’єктних типів (до яких відносяться масиви, класи, інтерфейси) – завжди за посиланням. Проілюструємо цю різницю на прикладі.
int x=5;
int y=x;
y++;
Чому дорівнює x? Звичайно 5, оскільки зміна значения y ніяк не впливає на значення x.
MyClass w = new MyClass();
MyClass z = w;
w.f = 5;
z.f = 6;
Чому дорівнює w.f ? Відповідь 6, оскільки і z, і w посилаються на одну і ту саму ділянку пам’яті.
В класах існують два типи змінних: одні належать самому класу, інші ж – різним методам класу.
Ті змінні, що описані не в методах, але в середині даного класу, називають полями класу. Вони доступні для всіх методів даного класу (це як мінімум).
Крім того, можна описувати змінні в середині метода класу. Такі змінні є локальними для метода і доступні тільки для цього метода.
Загальне правило: кожна змінна доступна лише в середині того блока (обмеженого фігурними дужками), в якому її описано.
І останнє. Як поля, так і локальні змінні можуть бути як базового типу, так і екземплярами класу.
В таблиці 2 наведено правила доступу до полів і методів, описаних за допомогою різних модифікаторів. Елемент, описаний public, доступний з будь-якого місця. Все, що описано private, доступно лише в середині класа. Якщо у елемента взагалі не указаний модифікатор рівня доступу, то такий елемент буде видно з підкласів-нащадків і класів того ж пакета. Саме цей рівень доступу використовується в Java за замовчуванням. Якщо треба зробити, щоб елемент крім того був доступний зовні пакета, але тільки підкласам того ж класа, якому він належить, його слід описати як protected. І, на сам кінець, якщо треба щоб елемент був доступний тільки підкласам, незалежно від того, чи знаходяться вони в даному пакеті, використовуйте комбінацію private protected.
Таблиця 2.2
Доступ до полів і методів для різних модифікаторів
private | friendly (модифікатор відсутній) | private protected | protected | public | |
той же клас | + | + | + | + | + |
підклас в тому ж пакеті | - | + | + | + | + |
незалежний клас в тому ж пакеті | - | + | - | + | + |
підклас в іншому пакеті | - | - | + | + | + |
незалежний клас в іншому пакеті | - | - | - | - | + |
З полями та методами можуть використовуватись всі специфікатори доступу, з класами – лише public і значення за замовчуванням.
Модифікатор static. Цей описувач може використовуватись як з полями, так і з методами. Для поля описувач static означає, що таке поле створюється в єдиному екземплярі незалежно від кількості об’єктів даного класу (звичайні поля – для кожного екземпляру класу). Статичне поле існує навіть тоді, коли немає жодного екземпляра класу. Статичні поля розташовуються Java-машиною окремо від об’єктів класу в момент першого звертання до цього класу. Розглянемо приклад:
public class Exam
{
int a = 10; // звичайне поле
static int cnt = 0; // статичне поле
public void print()
{
System.out.println("cnt=" + cnt);
System.out.println("a=" + a);
}
public static void main(String args[])
{ Exam obj1 = new Exam();
cnt++; // збільшуємо cnt на 1
obj1.print();
Exam obj2 = new Exam();
cnt++; // збільшуємо cnt на 1
obj2.a = 0;
obj1.print();
obj2.print();
}
}
У цьому прикладі поле cnt є статичним. На екрані для обох об’єктів буде виведено одне й те саме значення поля cnt. Це пояснюється тим, що воно існує в одному екземплярі.
По аналогії зі статичними полями статичні методи не прив’язані до конкретного об’єкта класу. Коли викликається статичний метод, перед ним можна вказувати не посилання, а ім’я класу. Наприклад:
class SomeClass
{ static int t = 0; // статичне поле
. . .
public static void f()
{ // статичний метод
. . .
}
public void g()
{ // звичайний метод
. . .
}
}
. . .
SomeClass MyClass1 = new SomeClass();
MyClass1.g();
SomeClass.f();
. . .
І, на сам кінець, оскільки статичний метод не пов’язаний з конкретним об’єктом, в середині такого метода не можна звертатися до нестатичних полів класу без посилання на об’єкт перед ім’ям поля (практично це означає, що такому методу треба передавати як параметр посилання на об’єкт). До статичних полів класу такий метод може звертатися вільно.
Модифікатор final. Цей описувач може використовуватись як з полями, так і з методами. Для полів – це простий засіб створення констант (в Java відсутня директива #define). Наприклад, final int SIZE = 5;
За замовчуванням константи записуються великими літерами. Крім того, для економного використання пам’яті константи звичайно роблять статичними.
Що стосується final-методів, то це такі методи, які не можуть бути перевизначеними в класах-нащадках.
Як відомо, існують два способи передачі параметрів:
за значенням;
за посиланням.
Правило таке: якщо передається базовий тип (int, char), то результат передається за значенням. Якщо передається об’єкт (наприклад, клас), то він передається за посиланням.
Якщо ви, наприклад, спеціалізуєтеся на анімації Web-сторінок, створили власний клас Animator і надалі вставляєте цей клас в усі свої програми. Щоб кожен раз не копіювати текст з одного файла в інший ви можете винести цей клас в окремий файл (за бажанням можна зробити його public). Якщо ви хочете тепер скористатися цим класом в іншій програмі, ви маєте імпортувати його, так саме, як і стандартні класи:
import Animator;
A якщо ви пишете велику програму, яка складається з багатьох класів. Оскільки кожен public-клас має знаходитися в окремому файлі, виникає необхідність якимось чином упорядкувати розміщення цих файлів. І такий спосіб існує.
Для упорядкування файлів класів в Java використовуються пакети. Кожен пакет можна розглядати як підкаталог на диску. Пакети – це набори класів. Вони нагадують бібліотеки, які існують в багатьох мовах. Звичайно пакети містять класи, логічно пов’язані між собою.
Щоб внести клас в пакет, необхідно скористатися оператором package, наприклад:
package game;
При цьому необхідно витримати дві умови:
Вихідний текст класа має знаходитись в тому ж каталозі, що і інші файли пакета (тобто цей каталог треба попередньо створити).
Оператор package має бути першим оператором в файлі.
Якщо файл є частиною пакета, справжнє ім’я класа складається з імені пакета, крапки та імені класа. Тому, якщо Ви внесли клас Animator в пакет game, щоб імпортувати його слід вказати повне ім’я класу:
import game.Animator;
Якщо ж вам необхідно використати в своїй програмі декілька класів з пакета game і ви не бажаєте імпортувати кожен клас окремо, виписуючи всі їх імена, ви можете імпортувати весь пакет, отримавши доступ одразу до всіх класів даного пакета:
import game.*;
І на сам кінець. Навіть нічого не імпортуючи, ви можете отримати доступ до деякого класу з пакету, вказуючи його повне ім’я при об’яві екземпляра класу:
game.Animator a;
Інтерфейси – це варіант множинного успадкування, яка є в C++, але відсутня в Java. Іншими словами, клас в Java не може успадкувати поведінку одразу кількох класів, але може реалізовувати одразу декілька інтерфейсів. Також клас може бути одночасно і нащадком одного класу, і реалізовувати один або кілька інтерфейсів.
В чому відмінність інтерфейсів від класів? Класи описують об’єкт, а інтерфейси визначають набір методів і констант, які реалізуються іншим об’єктом. Інтерфейси мають одне головне обмеження: вони можуть описувати абстрактні методи та поля final, але не можуть мати жодної реалізації цих методів. В прикладному відношенні інтерфейси дозволяють програмісту визначити деякі функціональні характеристики, не турбуючись про те, як потім ці характеристики будуть описані.
Наприклад, якщо деякий клас реалізує інтерфейс java.lang.Runnable він має містити метод run(). Тому java-машина може «всліпу» викликати метод run(), для будь якого Runnable-класу. Неважливо, які дії він при цьому виконує – важливо, що він є.
З точки зору синтаксису інтерфейси дуже схожі на класи. Головна відмінність полягає в тому, що жоден метод в інтерфейсі не має тіла та в ньому не можна об’являти змінні, а тільки константи.
В загальному випадку об’ява інтерфейса має вигляд: