|
|
ОБ’ЄКТНО ОРІЄНТОВАНЕ ПРОГРАМУВАННЯ Електронний посібник |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Модуль 2 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2. Складні типи даних. основні алгоритмічні
конструкції. методи (6 семестр) 2.1. Створення та використання об’єктів 2.2. Використання операторів та алгоритмічних конструкцій. Використання
циклів 2.3. Розробка та використання методів
В Java для роботи з об’єктами використовується єдиний
синтаксис. Об’єкт класу оголошується з допомогою посилання (reference). Загальна форма оголошення об’єкта класу без
виділення пам’яті для нього має наступний вигляд:
де ClassName – ім’я класу, для
якого створюється об’єкт з іменем objName, objName – ім’я посилання на об’єкт
класу ClassName. Вищенаведене
оголошення говорить про те, що ідентифікатор objName
є посиланням на об’єкт класу ClassName. Для посилання потрібно виділити пам’ять (ініціалізувати посилання) з допомогою оператора new як показано нижче:
Якщо не виділити
пам’ять для посилання і звернутись до нього як до об’єкта класу, то виникне
помилка. Існує й інша
загальна форма оголошення об’єкта класу. У цьому випадку пам’ять виділяється
при його оголошенні:
Виділення пам’яті
для посилання на об’єкт класу ще називається "приєднання" об’єкта до посилання. Приклади створення
об’єктів різних класів: Приклад 1. Створення об’єкта класу CLine,
що реалізує лінію на координатній площині.
Як видно з коду, у
функції main() оголошуються
два посилання з іменами line1, line2 на об’єкти класу CLine. Для цих посилань виділяється
пам’ять з допомогою оператора new. Потім, для
об’єкта line2 пам’ять заново перевизначається.
Стара пам’ять буде звільнена за чергового "збору" сміття. Приклад 2. Створення об’єкта класу CName,
що реалізує ім’я.
–
регістри. У цьому випадку
дані зберігаються всередині процесора. У регістрах дані обробляються швидше
за все. Однак кількість регістрів є строго обмеженою. Компілятор використовує
регістри в міру необхідності. У Java немає
безпосередніх команд, щоб зберігати усі дані тільки в регістрах. Навіть у
потужних мовах C/C++ команди-вказівки для розміщення даних у регістрах носять
тільки рекомендаційний характер; –
стек. Для програми стек
розміщується в загальній оперативній пам’яті (RAM). Стек організовується з
використанням покажчиків стеку. Стек працює за принципом LIFO (Last-In-First-Out) – останній прийшов, перший вийшов.
Така організація є зручною, коли потрібно виділяти пам’ять для локальних
функцій (методів) різних рівнів вкладень. У стеку розміщуються тільки
покажчики на об’єкти. Самі об’єкти розміщуються в "купі"
(heap, або "купа"). Покажчик стеку рухається донизу, якщо потрібно
виділити пам’ять, і доверху, якщо пам’ять звільняється. Таким чином, за
швидкодією стек поступається тільки регістрам. Однак стек не володіє такою
гнучкістю, як "купа", тому що компілятору потрібно знати життєвий цикл
даних, розміщених в стеку; –
"купа" (heap). Це сховище загального призначення, яке розміщується
в оперативній пам’яті (RAM). Тут зберігаються усі об’єкти (екземпляри
об’єктів) Java. "Купа" є більш гнучкою порівняно зі стеком,
тому що компілятор не витрачає додаткових зусиль на визначення тривалості
існування об’єктів, що знаходяться в "купі". У програмі створення об’єкта відбувається з
використанням оператора new. У результаті виділяється
пам’ять з "купи". Однак, виділення пам’яті з "купи"
займає більше часу, ніж у стеку. Слід зауважити, що потужні мови C/C++
підтримують явне створення об’єктів як в стеку, так і в "купі"; –
постійне сховище. У програмах часто використовуються дані, які є
незмінними. До таких даних відносять константи (наприклад, рядкові
константи). Ці дані доцільно вбудовувати прямо в код програми. Інколи
константи розміщуються в постійній статичній пам’яті (ROM); –
зовнішнє сховище. Зовнішнім сховищем можуть бути довготривалі (persistent) носії інформації, наприклад, жорсткий
диск комп’ютера або носії інформації
віддалених комп’ютерів мережі. Цей вид зберігання даних дозволяє зберігати
об’єкти на носіях інформації, а потім відновлювати їх для зберігання в
оперативній пам’яті. Об’єкти
зберігаються в "купі" (heap). Посилання на
об’єкти зберігаються в стеку.
Java, як і інші мови програмування, підтримує умовні інструкції
та цикли, що визначають порядок виконання інструкцій у програмі. В
англійській мові для цього поняття застосовують термін control
flow – керування потоком. Перед тим як
знайомитись з керуючими структурами, спочатку необхідно ознайомитися з
блоками. Блок, або складений оператор, – це будь-яка кількість простих інструкцій, які
оточені парою фігурних дужок. Блок визначає область видимості ваших змінних.
Блоки можуть бути вкладені в середину інших блоків. Ви вже зустрічалися з
блоками при створенні найпростіших програм у методі main().
Умова має бути
оточена дужками і якщо умова задовольняється (true),
буде виконана інструкція за умовою, інакше вона виконана не буде, а буде
виконана наступна інструкція після умовної інструкції. Приклад: Зазвичай необхідно
виконати не одну інструкцію, в такому випадку інструкції розміщають у блоці:
В такому разі, за
істинності умови, виконуються всі інструкції у блоці, якщо умова невірна, то
виконується наступна інструкція після закриваючої дужки блоку.
Інструкції if можуть йти одна за
одною без використання else:
Для того, щоб
програма була читабельнішою, бажано застосовувати
фігурні дужки:
Вони нічого не
змінюють, але вираз стає зрозумілішим. Інструкція чи блок інструкцій
виконується лише в разі виконання усіх умов. Щоправда цю
інструкцію можна також переписати, ускладнивши умову, використавши булевий
оператор і (&&):
Це дає можливість
перевірити ряд умов, якщо попередні умови не виконуються.
Загальний вигляд: while (умова) інструкція; Якщо немає фігурних
дужок, то перша інструкція, яка йде після оголошення циклу, вважається тілом
циклу. Всі інші інструкції знаходяться поза циклом. Якщо в циклі повинні
виконуватись кілька інструкцій, то необхідно використати фігурні дужки. Вони
також можуть використовуватись за однієї інструкції заради кращого
візуального розуміння коду.
Результат
виконання: Спробуйте відгадати число від 0 до 10 Введіть число від 0 до 10: 6 Не вгадали. Спробуєте ще раз? (Y/N)y Введіть число від 0 до 10: 7 Вгадали!!! Спробуєте ще раз? (Y/N)
n Програма генерує
випадкове число за кожного повтору циклу і пропонує вгадати його. Після вводу
користувачем числа – виводить відповідне повідомлення вгадано чи ні. Після
цього пропонується здійснити нову спробу. Якщо користувач вводить з
клавіатури "Y" або "y", то гра продовжується, якщо введе щось інше, то
завершується. Для генерації
випадкових чисел використано клас Random, що
містить методи для генерації випадкових чисел. Зокрема у нашій програмі
використано метод nextInt(), який
дозволяє генерувати випадкові числа. Для зчитування з
клавіатури використано клас Scanner, який
був доданий в Java 5.0, для зручного вводу з клавіатури. Метод nextInt() – читає ціле число, next()
– читає цілий рядок з клавіатури. Для того, щоб
переконатися, що користувач хоче продовжити гру, використано метод equals() з класу String
– Strint1.equals (String2), що перевіряє чи один рядок (String1)
тексту рівний іншому (String2). У вищенаведеній
програмі пояснення потребують три рядки. Для початку вам необхідно лише в
загальному зрозуміти їхнє призначення.
Нам необхідний генератор
цілих чисел, який реалізує класс Random з пакету java.util. Для цього ми
імпортуємо відповідний клас (в С/С++ аналогом є підключення бібліотеки). Далі
в програмі створюємо змінну generator, яка
вказуватиме на екземпляр класу random і дозволятиме звернення до методів цього класу. New Random() –
створює відповідний об'єкт. Для генерації випадкових чисел ми використовуємо
метод nextInt() класу
Random. Якщо необхідно, щоб
умова виконувалася хоча б один раз, можна скористатися циклом з післяумовою do/while: do інструкція while (умова); Зокрема в програмі
з вгадуванням чисел логічніше було б застосувати саме цей цикл, оскільки
необхідне хоча б одне виконання тіла циклу.
Цикл for (цикл з лічільником) – доволі часто вживаний цикл. Він застосовується за
необхідності виконати інструкції певну кількість разів з одночасним
збільшенням або зменшенням певної змінної. Часто використовується для
здійснення перебору певних масивів даних, зокрема також для сортування
масивів. Приклад використання:
Наведений вище
приклад виведе на консолі в стовпчик числа від 1 до 10. Як бачимо, в умові
циклу перший слот відводиться для ініціалізації
змінної, причому оголосити змінну можна і в іншому місці. Другий слот – для умови, яка перевіряється перед виконанням
ітерації, третій слот – вказує як модифікувати
змінну-лічильник. Тобто в наведеному прикладі за кожного виконання ітерації,
лічильник "і" буде збільшуватися на одиницю, поки не стане рівним
десяти. Найчастіше цей цикл
використовується для перебору елементів масиву. Масив – це
впорядкований набір даних одного типу. Найпростіший масив можна оголосити та ініціалізувати таким чином: int
a[]={1, 5, 6, 1, 3};. Для того, щоб звернутися до певного елемента
масиву, використовуються квадратні дужки з відповідним індексом елемента.
Наприклад, а[3] – звернення до четвертого елемента масиву (номери
елементів відраховуються з нуля).
Починаючи з Java
SE 5.0, в мові з’явився новий цикл – покращений for,
призначення якого – перебір елементів масиву або подібних до масиву типів
даних (колекції).
Використання цього
циклу дозволяє уникнути проблем, пов’язаних з помилками при заданні умови в
класичному циклі for. В інших мовах програмування
цикл такого виду так і називається foreach,
проте, щоб уникнути необхідності значних змін в пакетах, в Java
пішли простішим шляхом і перевантажили цикл for. У Java
відсутня інструкція goto, яка дозволяла
переходити в будь-яке місце в програмі. Її використання давно вважається поганим
стилем програмування, оскільки робить текст програми заплутаним. Про це,
зокрема, писав ще Дональд Кнут і він же
зазначав, що інколи все таки корисно її застосовувати, щоб припинити
виконання певного методу, циклу чи блоку і вийти за їхні межі. Для цієї мети
в java існують спеціальні інструкції. Зокрема
інструкцію break можна використати для передчасного
виходу з циклу. Якщо ми використовуємо вкладені цикли (один цикл в
іншому), то інструкція break припинить цикл,
в якому вона знаходиться. Якщо вона знаходиться у внутрішньому циклі, то він
припинить своє виконання, а зовнішній же цикл буде виконуватись і далі. Якщо
потрібно повністю припинити виконання і внутрішнього і зовнішнього, то
використовується інструкція break з міткою. Якщо ж нам не
потрібно виходити з циклу, а лише припинити певну його ітерацію, то
для цього використовується інструкція continue,
яка переносить порядок виконання до заголовку інструкції. Щоправда завжди
можна обійтися без цих інструкцій, змінивши логіку програми. Деякі з
програмістів уникають використовувати інструкції break
та continue. Інструкція if/else може бути доволі
громіздкою, якщо необхідно здійснити множинний вибір з багатьох
альтернатив. Тож як і в С/C++, в java існує
інструкція switch, яка дозволяє здійснити
вибір з багатьох варіантів. Щоправда вона дещо незграбна і деякі програмісти
вважають за краще уникати її використання.
Якщо пропустити
інструкцію break, то всі інші інструкції будуть
також виконані. Тобто якщо справдиться умова першого варіанта, то будуть
здійснені ще й дії, вказані для виконання у всіх інших варіантах. До версії Java 7, яка вийшла у 2011 році, case
мітка мала бути лише цілим числом або нумерованою константою.
За допомогою
методів ми виносимо текст повторюваного коду програми окремо в тіло методу, після
чого можна викликати цей метод з будь-якого місця програми, безліч разів.
Виклик методу
здійснює наступна інструкція: назва_методу
(параметри). Взагалі в термінології мов програмування для виклику методу
використовуються аргументи, а в самому методі – це вже параметри,
оскільки передаються лише значення змінних, а не самі змінні. Аргументи та
параметри мають бути одного і того ж типу. Якщо ми передаємо цілочисельне значення, то і параметр повинен бути цілочисельним тощо. Тобто в методі створюються нові
змінні. В деяких мовах, наприклад в С++, як аргумент можна передати посилання
на певну змінну, таким чином її можна буде модифікувати в функції через
вказівник на цю змінну. В Java в метод
передаються лише значення змінних, тому розрізнення аргументів і
параметрів не настільки суттєве, тож ми і там і там використовуватимемо
термін "параметр". Об'єкти ж в методи передаються за посиланням.
Тобто, при передачі в якості аргументу об'єкта, буде передане посилання на
об'єкт, а не створений новий об'єкт. Повернемось до прикладу
з сейфом. Повторюваними є присвоювання значень змінним, обчислення та
виведення об’ємів. Тому корисно буде створити два методи safeValue (double width, double height, double depth) та safeVolume (). Перший для
присвоєння змінним значень, а другий для обчислення об'єму.
Як бачимо, код
програми досить простий. Тепер набагато легше модифікувати програму, додаючи
нові сейфи. Крім того, можна, наприклад, вивести повідомлення з інформацією
про об’єм, розмістивши його в метод safeVolume() або зовсім в окремий метод, наприклад, printVolume(). Слід зауважити щодо
назв змінних-параметрів. Так, для висоти, ширини та глибини в методі safeValue() вибрані
назви pWidth, pHeight, pDepth. Вони могли б мати назви і просто width, height, depth, але тоді б вони перекрили
доступ до однойменних змінних класу. В такому випадку, щоб звернутися до
змінних класу з методу, необхідно вживати ключове слово this. Наприклад: this.height=height – тут ми присвоюємо змінній класу this.height одержаний методом параметр height. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||