У вас вопросы?
У нас ответы:) SamZan.net

Вступ Приступаючи до вивчення нової мови корисно поцікавитися які вихідні дані можуть опрацьовуватися

Работа добавлена на сайт samzan.net: 2015-07-05

Поможем написать учебную работу

Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.

Предоплата всего

от 25%

Подписываем

договор

Выберите тип работы:

Скидка 25% при заказе до 8.4.2025

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

Урок 2. Базовий курс Java

Реквізити: Текст лекції і опис класу System

2.1.  Вступ

Приступаючи до вивчення нової мови, корисно поцікавитися, які вихідні дані можуть опрацьовуватися засобами цієї мови, в  якому вигляді їх можна задавати і які стандартні методи опрацювання цих даних закладені в мову.  Це досить нудне заняття, тому що в кожній розвиненій мові програмування багато типів даних і ще більше методів їх використання.   Однак невиконання цих правил приводить до появи скритих помилок, виявити які часто буває дуже важко. Але в кожному ремеслі спочатку приходиться  "грати гами", і ми не можемо цього уникнути.

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

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

2.2.  Перша програма на Java

Java програма існує у вигляді класу. Починається службовим словом class, за яким слідує імя класу , а далі, в фігурних дужках, тіло класу – поля змінних і методи. Ось наша перша Java програма:

class Zero {}

Програма може бути написана в будь-якому текстовому редакторі, наприклад Notepad.  Потім її треба зберегти у  файлі, імя якого співпадає з іменем класу і з розширенням .java, в даному випадку  Zero.java. Потім програму треба скомпілювати, що в даному випадку означає переведення її в байт коди. Для цього треба мати набір файлів JDK – Java Developer Kit,  який можна безкоштовно зкачати з Інтернет або зкопіювати з іншого компютера. У мене ця папка знаходиться на диску С. Щоб спростити компіляцію і запуск програми, я збережу цей файл також на диску С. На вашому компютері версія  JDK може бути відмінною від моєї (вони обновлюються майже щорічно). Те ж саме стосується і її місця знаходження на диску, тому треба при потребі внести корективи у нижче наведену адресу папки bin. Знаходимо в компютері програму  Командная строка і відкриваємо її. Ось як було на моєму компютері.

Рис. 2.1. Програма Командная строка

Нам треба повернутися до корінної директорії С, де знаходиться  JDK. Для цього набираємо в командному рядку сd C:\  і натискаємо Enter (cd – change directory). Результат ви бачите нижче.

Рис. 2.2.  Програма Командная строка готова працювати з файлами диску С

Тепер викликаємо компілятор javac, що знаходиться в папці bin і вказуємо йому файл для компіляції. Тиснемо Enter і компілятор створить файл с байт-кодами, дасть йому імя Zero.class и запише цей файл в поточний каталог – перевірте. Якщо все пройшло як треба, Командная строка повернеться до корінної директорії С.

Рис. 2.3. Програма скомпільована

Залишилось викликати інтерпретатор java (JVM), передавши йому в якості аргумента імя класу (а не файла). Після натиску  Enter нас чекає перше розчарування - JVM не змогла запустити програму на виконання і сповістила чому процес (thread)  виключився (exception). В нашому класі відсутній стартер – метод main().

Рис. 2.4. Невдала спроба запустити програму на виконання

Ситуація аналогічна з С++, але трохи складніша. Попробуємо її виправити. 

class Zero{

public static void main(String[] args){}

}

Чому крім знайомого нам void перед  main()  зявилося ще й  public static, а в аргументі String[] args  я поясню пізніше, а поки що візьміть це за правило. Перекомпілюйте файл і запустіть програму заново.

Рис. 2.5. Програма спрацювала

Цього разу все получилося, хоча програма і спрацювала вхолосту. Тепер заставимо її зробити щось корисне.

2.3. Перша повноцінна програма на мові Java

По давній традиції, що започаткована в мові С, підручники по мовах програмування починаються з програми, яка виводить на екран привітання  "Hello, World!". He будемо порушувати цю  традицію.

Лістинг 2.1. Перша повноцінна програма на мові Java

class Zero{

public static void main(String[] args){

System.out.println("Hello, World!");

}

}

Перекомпілюйте цю програму і запустіть на виконання. Цього разу все повинно вийти як треба.

Рис. 2.6. Перша результативна Java програма

На цьому простому прикладі можна помітити ряд суттєвих особливостей мови  Java.

  •  Всяка програма являє собою один або декілька  класів, в цьому найпростішому прикладі тільки один клас (class).
  •  Початок класу позначачється  службовим словом class, за яким іде імя класу, що вибирається довільно, в даному випадку  Zero. Все, що міститься в  класі, записується  в фігурних дужках і складає  тіло класу (class body).
  •  Всі дії виконуються за допомогою методів обробки інформації, коротко говорять просто  метод (method). Цей термін вживається в мові Java замість назви  "функція", що використовується в інших мовах.
  •  Методи розрізняються по іменах. Один із методів обовязково повинен називатися  main, з нього починається виконання  програми. В нашій найпростішій програмі тільки один метод, а значить, імя йому  main .
  •  Як і  положено функції, метод завжди видає в результат (частіше говорять, повертає (returns)) тільки одне значення, тип якого обовязково указується перед іменем метода. Метод може і не повертати ніякого значення, виконуючи  роль процедури, як у нашому випадку. Тоді замість типу  значення записується слово void, як це і зроблено у прикладі.
  •  Після імені метода в дужках, через кому, перечисляються аргументи (arguments) - або параметри метода. Для кожного аргумента указується його тип і, через пробіл, імя. В прикладі тільки один аргумент, його тип — массив, що складається з рядків символів. Рядок символів — це вбудований в Java API тип String, а квадратні дужки — ознака масива. Імя масива може бути довільним, в прикладі вибрано імя args.
  •  Перед типом значення, що повертається методом, можуть бути записані модифікатори (modifiers). В прикладі їх два: слово public означає, що цей метод доступний звідусіль; слово static забезпечує можливість виклику метода main () в самому початку виконання програми. Модифікатори взагалі необовязкові, але для метода main () вони необхідні.

Зауваження.

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

  •  Все, що містить метод, тіло метода (method body), записується в фігурних дужках.

Єдину дію, яку виконує метод main () в прикладі, заключається у виклику іншого метода зі складним іменем System.out.println() і передачі йому на опрацювання одного аргумента, текстової константи "Hello, World!". Текстові константи записуються  в лапках, які являються тільки обмежувачами і не входять в склад текста.

Складне імя System.out.println() означає, що в класі System, який входить в Java API, визначається змінна з іменем out, котра містить екземпляр одного із класів Java API, класа PrintStream, В ньому є метод println() . Все це стане ясно пізніше, а поки що просто будемо писати це довге імя.

Дія метода println () заключається у виведенні свого аргумента у вихідний потік, пов’язаний, як правило, з виведенням на екран текстового термінала, у вікно MS-DOS Prompt або Command Prompt , в залежності від вашої системи. Після виведення курсор переходить на початок наступного рядка екрана, на що указує закінчення  ln, слово println — скорочення слів print line. У складі  обєкта out єсть і метод print (), що залишає курсор в кінці виведеного рядка. Зрозуміло, це прямий вплив мови Pascal.

Відкрийте опис класу System  в однойменному файлі папки Java2 і ознайомтеся з іншими методами класу і його полів, в першу чергу поля  out.

Зробимо зразу важливе зауваження. Мова  Java розрізняє заглавні і прописні літери, імена main, Main, MAIN різні з "точки зору" компілятора Java. В прикладі важливо писати String, System з заглавної літери, a main з маленької. Але всередині текстової константи не має значення, писати World чи world, компілятор взагалі не "дивиться" на неї, різниця буде помітна лише на екрані.

Зауваження

Мова Java розрізняє прописні і заглавні літери.

Свої імена можна записувати як завгодно, можна було б дати класу імя helloworld чи Helloworld, але між Java-програмістами заключено догвір під іменем "Code Conventions for the Java Programming Language", який можна знайти за адресою http://java.sun.com/docs/codeconv/index.html. Ось  декілька пунктів цього договора:

  •  імена класів починаються з заглавної літери; якщо імя містить декілька слів, то кожне слово починається із заглавної літери;
  •  імена методів і змінних починаються з прописної літери; якщо ім’я містить декілька слів, то кожне наступне  слово теж починається з прописної літери;
  •  імена констант записуються повністю заглавними літерами; якщо ім’я містить декілька  слів, то між ними ставиться знак підкреслювання.

Звичайно, ці правила необов’язкові, хоча вони і входять в JLS, п. 6.8, але дуже полегшують розуміння  кода і надають програмі характерний для Java стиль.

Стиль визначають не лише імена, але і розташування  тексту програми по рядках, наприклад, розташування фігурних дужок: чи залишати відкриваючу дужку в кінці рядка з  заголовком класа або метода чи переносити на наступний рядок? Чомусь це дрібне питання викликає запеклі суперечки, деякі засоби розробки, наприклад JBuilder, навіть пропонують  вибрати певний стиль розташування фігурних дужок. Деякі фірми встановлюють свій, внутріфірменний стиль. Ми постараємося слідувати стилю "Code Conventions" і в тому, що стосується розбиття текста програми на рядки (компілятор же розглядає всю програму як один довгий рядок, для нього програма — це просто послідовність символів), і в тому, що стосується відступів (indent) у тексті.

Порада

Називайте файл з програмою іменем класа, що містить метод main (), дотримуйтесь регістру літер.

Зауваження:

Не указуйте розширення class при виклику інтерпретатора.

2.4.  Коментарі:

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

  •  за двома похилими рисками підряд //, без пробілу між ними, починається коментар, що продовжується до кінця рядка;
  •  за похилою рискою і зірочкою /* починається коментар, котрий може займати декілька рядків, до зірочки і похилої риски */ (без пробілів між цими знаками).

Коментарі дуже зручні для читання і розуміння коду, вони перетворюють програму в документ, що описує її дії. Програму з хорошими коментарями називають самодокументованою. Тому в Java введені коментарі третього типу, а в склад JDK — програму javadoc, що поміщає ці  коментарі в окремі файли формату HTML і створює гіперпосилання між ними: за похилою рискою і  двома зірочками підряд, без пробілів, /** починається коментар, котрий може займати декілька рядків до зірочки з однією похилою рискою  */ і опрацьовується програмою javadoc. В такий коментар можна вставить вказівки програмі javadoc, котрі починаються  символом @. Якраз так створюється документація в JDK. Додамо коментарі до нашого прикладу (лістинг 1.2).

Лістинг 2.2. Перша програма з коментарями

class HelloWorld{ 

/**

* Пояснення змісту і особливостей програми...

* @author Імя Прізвище (автора)

* @version 1.0 (це версія програми)

*/

// HelloWorld — це лише імя

// Наступний метод починає виконання програми

public static void main(String[] args){ // args не використовується

/* Наступний метод просто виводить свій аргумент  на екран дисплея */

System.out.println("Hello, 21st Century World!");

// наступний виклик закоментований, метод не буде виконуватися

// System.out.println("Farewell, 20th Century!");

}

}

Зірочки на початку строчки ніякої ролі не відіграють, вони лише допомагають нам слідкувати за коментарем. Приклад, звичайно, перевантажений поясненнями (це поганий стиль), тут просто показані різні форми коментарів.

2.5.  Константи

В мові Java можна записувати константи різних типів у різних виглядах. Перечислимо їх.

2.5.1. Цілі константи

Цілі константи можна записувати в трьох системах числення:

  •  в десятичній формі: +5, -7, 12345678;
  •  у восьмеричній формі, починаючи з нуля: 027, -0326, 0777; в запису таких констант недопустимі цифри 8 і 9;

Зауваження

Число, що починається з нуля, записано в восьмеричній формі, а не в десятковій.

  •  в шістнадцятирічній формі, починаючи з нуля і латинської літери х або X: 0xff0a, 0xFC2D, 0x45a8, 0X77FF; тут заглавні і  прописні літери не розрізняються.

Цілі константи зберігаються у форматі типу int (див. нижче).

В кінці цілої константи можна записати літеру заглавну L або прописну l, тоді константа буде зберігатися в довгому форматі типу long (див. нижче): +25L, -0371, 0xffL, 0xDFDF1.

Порада

Не використовуйте при запису довгих цілих констант заглавну латинську літеру l, її легко переплутати з одиницею.

2.5.2.  Дійсні константи

Дійсні константи записуються лише в десятковій системі числення в двох формах:

  •  з фіксованою точкою: 37.25, -128.678967, +27.035;
  •  з плаваючою точкою: 2.5е34, -0.345е-25, 37.2Е+4; можна писати заглавну або прописну латинську літеру Е; пробіли і дужки  недопустимі.

В кінці дійсної константи можна поставити літеру F або f, тоді константа буде зберігатися  в форматі типу float (див. нижче): 3.5f, -45.67F, 4.7e-5f. Можна приписати і літеру D (або d): 0.045D, -456.77889d, що означає  тип double, але це вже зайве, оскільки дійсні константи і так зберігаються  в форматі типа double.

2.5.3.  Символьні константи

Для запису одиноких символів використовуються наступні форми.

  •  Друковані символи можна записувати в апострофах: 'а', 'N', '?'. Замініть у програмі HelloWorld команду

System.out.println("Hello, World!");  на

System.out.println('H');

і випробуйте її. Буде надрукована літера Н. Якщо ж ви напишете

System.out.println('Hello, World!');

то компілятор відмовиться працювати з такою програмою.

Керуючі символи записуються в апострофах з оберненою похилою рискою:

  •  '\n' — символ переводу рядка newline з кодом ASCII 10;
  •  '\r' — символ повернення каретки CR з кодом 13;
  •  '\f' — символ переводу сторінки FF з кодом 12;
  •  '\b' — символ повернення на крок BS з кодом 8;
  •  '\t' — символ горизонтальної табуляції НТ з кодом 9;
  •  '\\' — обернена похила риска;
  •  '\"' — лапка;
  •  '\'' — апостроф.
  •  Код будь-якого символу з десятичним кодуванням від 0 до 255 можна задати, записавши його не більше ніж трьома цифрами у восьмеричній системі числення в апострофах після оберненої похилої риски: '\123' — буква S, '\346' — буква ц . Не рекомендується використовувати цю форму запису для друкованих і керуючих  символів, перечислених у попередньому пункті, оскільки компілятор зараз же переведе восьмеричний запис у вказану вище форму. Найбільший код '\377' — десяткове число 255.
  •  Код будь-якого символу в кодуванні Unicode набираеться в апострофах після оберненої похилої риски і  латинської літери u  рівно чотирма шістнадцятирічними цифрами: '\u0053' — буква S, '\u0416' — знак питання ?.

Випробуйте програму з командами

System.out.println('\123'); System.out.println('\346'); System.out.println('\u0053'); System.out.println('\u0416');

Символи зберігаються в форматі типу char (див. нижче).

Примітка

Заглавні  російські літери в кодуванні Unicode займають діапазон від '\u0410' — заглавна літера А, до '\u042F' — заглавна Я, прописні літери '\u0430' — а, до '\044F' — я.

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

Зауваження. Компілятор і виконуюча система Java працюють тільки з кодуванням Unicode.

Порада.  Користуйтеся  Unicode напряму лише у крайніх випадках

2.5.4.  Рядкові константи

Рядки символів поміщаються в лапки. Керуючі символи і коди записуються в рядках точно так  же, з оберненою похилою рискою, але без апострофів, і викликають ті ж самі дії. Рядки можуть розташовуватися лише в одному рядку вихідного кода, не можна відкриваючі лапки поставити  в одному рядку, а закриваючі — в наступному.

Ось декілька прикладів:

"Цей рядок\nз переносом"

"\"Динамо\" — Чемпіон!"

Примітка

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

Для рядкових констант визначена операція зєднання, позначається плюсом.

" Зєднання " + "рядків" дає в результаті рядок "Зєднання рядків".

2.6.  Імена 

Імена (names) змінних, класів, методів і інших обєктів можуть бути простими (загальна назва — ідентифікатори (idenifiers)) і складними (qualified names). Ідентифікатори в Java складаються з так званих літер Java (Java letters) і арабських цифр 0 - 9, причому першим символом ідентифікатора не може бути цифра. (Дійсно, як розуміти запис 2е3: як число 2000,0 чи як імя змінної?) В число літер Java обов’язково входять прописні і заглавні латинські літери, знак долара $ і знак 'підкреслювання _, а також символи національних алфавітів.

Зауваження

Не вживайте в іменах знак долара. Компілятор Java використовує його  для запису імен вкладених  класів.

Ось приклади правильних ідентифікаторів:

a1 , my_var, var3_5, _var, veryLongVarName, aName, theName, a2Vh36kBnMt456dX

В іменах краще не вживати прописну літеру  l, котру легко сплутати з одиницею, і літеру  О, котру легко прийняти за нуль.

Не забувайте про рекомендації "Code Conventions".

В класі Character, що входить до складу Java API, є два методи, що перевіряють, чи придатний  даний символ для використання в ідентифікаторі: isJavaIdentifierStart(), перевіряє, чи являється символ літерою Java, придатною для першої літери ідентифікатора і isJavaldentifierPart(), що виясняє, чи можна взагалі вживати цей символ в ідентифікаторі. Випробуйте наступні дві програми і ви побачите який із ASCII символів на що придатний.

class Test {

public static void main(String[] args) {

for (int i = 0; i < 256; i++)

{ if (Character.isJavaIdentifierStart((char)i))

System.out.println(Integer.toString(i)+ "  " + (char)i + "  is Java Identifier Start Symbol" );

                     else

   System.out.println(Integer.toString(i)+ "  " + (char)i + "  isn't Java Identifier Start Symbol" );

 }

}

}

і

class Test {

public static void main(String[] args) {

 for (int i = 0; i < 256; i++)

 { if (Character.isJavaIdentifierPart((char)i))

 System.out.println(Integer.toString(i)+ "  " + (char)i + "  is Java Identifier Part Symbol" );

else

 System.out.println(Integer.toString(i)+ "  " + (char)i + "  isn't Java Identifier Part Symbol" );

   }

 }

}

Службові слова Java, такі як class, void, static, зарезервовані, їх не можна використовувати в якості ідентифікаторів .

Складне імя (qualified name) — це декілька ідентифікаторів, розділених точками, без пробілів, наприклад, нам уже зустрічалоя імя System.out.println.

Порада.  Ознайомтеся з іншими методами класу Character по одноіменному файлу.

2.7.  Примітивні типи даних і операції

2.7.1. Загальна класифікація

Всі типи вихідних даних, вбудованих в мову Java, діляться на дві групи: примітивні типи (primitive types) и посилочні типи (reference types).

Посилочні типи діляться на масиви (arrays), класи (classes) і інтерфейси (interfaces).

Примітивних типів всього вісім. Їх можна розділити на логічний (інколи говорять булів) тип boolean і числові (numeric).

До числових типів відносяться цілі (integеr) і дійсні (floating-point) типи.

Цілих типів пять: byte, short, int, long, char.

Символи можна використовувати всюди, де вживається тип int, тому JLS причисляє їх до цілих типів. Наприклад, їх можна використовувати в арифметичних обчисленнях, скажімо, можна написати 2 + 'b', до двійки буде доданий ASCII код 98 літери 'b' і в результаті додавання одержимо 100.

Нагадаємо, що в записі 2 + "b" плюс розуміється як зєднання рядків, двійка буде перетворена в рядок, в результаті одержимо рядок "2b".

Дійсних типів два: float і double. Оскільки по імені змінної неможливо визначити її тип, всі змінні обовязково повинні бути описані перед їх використанням. Описання полягає в тому, що записується ім’я типа, потім, через пробіл, список імен змінних, розділених комою. Для всіх або деяких змінних  можна вказати початкові значення після знака рівності, котрими можуть бути будь-які  константні вирази того ж типа. Описання кожного типу закінчується точкою з комою. В програмі може бути скільки завгодно описань кожного типу.

Зауваження для спеціалістів 

Java — мова зі строгою типізацією (strongly typed language).

Розберемо кожний тип детальніше.

2.7.2.  Логічний тип

Значення логічого типа boolean виникають в результаті різних порівнянь, вроді 2 > 3, і використовуються, головним чином, в умовних операторах і операторах циклів. Логічних значень всього два: true (істина) і false (хиба). Це службові слова Java. Описання змінних цього типа виглядає так:

boolean b = true, bb = false, bool2; 

Над логічними даними можна виконувати операції присвоювання, наприклад, bool2 = true, в тому числі й сумісні з логічними операціями; порівняння на рівність b == bb і на нерівність b != bb, а також логічні операції.

2.7.3. Логічні операції

Логічні операції:

  •  заперечення (NOT) ! (позначається знаком оклику);
  •  кон’юнкція (AND) & (амперсанд);
  •  диз’юнкція (OR) | (вертикальна риска);
  •  виключне АБО (XOR) ^ (каре).

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

Таблиця 1.1. Логічні операції

b1 

b2 

!b1 

b1&b2 

b1|b2 

b1^b2 

true

true

false

true

true

false

true

false

false

false

true

true

false

true

true

false

true

true

false

false

true

false

false

false

Словами ці правила можна виразити так:

  •  заперечення змінює значення істинності;
  •  конюнкція істинна, тільки якщо обидва операнди істинні;
  •  дизюнкція хибна, тільки якщо обидва операнди хибні;
  •  виключне АБО істинно, тільки якщо значення операндів різні.

Зауваження 

Якби Шекспір був програмістом, то фразу "То be or not to be" він написав би так: 2b | ! 2b.

Крім перечислених чотирьох логічних операцій єсть ще дві логічні операції скороченого обчислення:

  •  скорочена конюнкція (conditional-AND) &&;
  •  скорочена дизюнкція (conditional-OR) ||.

Здвоєні знаки амперсанда і вертикальної риски слід  записувати без пробілів.

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

Це правило дуже зручне і вправно застосовується , наприклад, можна записувати вирази (n != 0) && (m/n > 0.001) або (n == 0) || (m/n > 0.001) не боячись ділення на нуль.

Зауваження 

Практично завжди в Java використовуються якраз скорочені логічні операції.

2.7.4.  Цілі типи

Специфікація мови Java, JLS, визначає розрядність (кількість байтів, що відводяться  для зберігання значень типа в оперативній памяті) і діапазон значень кожного типа. Для цілих типів вони наведені в табл. 1.2.

Таблиця 1.2. Цілі типи

Тип 

Розрядність (байт) 

 Діапазон 

byte

1

от -128 до 127

short

2

от -32768 до 32767

int

4

от -2147483648 до 2147483647

long

8

от -9223372036854775808 до 9223372036854775807

char

2

від '\u0000' до '\uFFFF' , в десятковій формі від 0 до 65535

Між іншим, для Java розрядність не стільки важлива, на деяких комп’ютерах вона може відрізнятися від наведеної   в таблиці, а от діапазон значень повинен витримуватись беззастережно.

Хоча тип char займає два байти, в арифметичних обчисленнях він працює як тип int, йому виділяється 4 байти, два старших байти заповнюються нулями.

Приклади виздначення змінних цілих типів:

byte b1 = 50, b2 = -99, bЗ;

short det = 0, ind = 1;

int i = -100, j = 100, k = 9999;

long big = 50, veryBig = 2147483648L;

char c1 = 'A', c2 = '?', newLine = '\n';

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

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

Наприклад, значення 50 змінної b1, визначеної вище, буде зберігатися в одному байті з вмістом 00110010, а значення -99 змінної b2 — в байті із вмістом, котрий обчислюємо так: число 99 переводимо в двійкову форму, одержимо 01100011, міняємо одиниці з нулями, одержуємо 10011100, і прибавляємо одиницю, одержавши нарешті байт зі вмістом 10011101.

Зміст всіх цих складностей в тому, що додавання  числа з його доповняльним кодом в двійковій арифметиці дасть в результаті нуль, старший біт просто втрачається. Це означає, що в такій дивній арифметиці доповняльний код числа являється протилежним йому числом, числом с оберненим знаком. А це, в свою чергу, означає, що замість того, щоб відняти від числа А число В, можна до А прибавить доповняльний код числа В. Таким чином, операція віднімання виключається із набору машинних операцій.

Над цілими типами можна виконувати масу операцій. Їх набір визначився в мові С, він виявився зручним і кочує з мови в мову майже без змін. Особливості застосування цих операцій в мові Java показані на прикладах.

2.7.5. Операції над цілими типами 

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

2.7.5.1. Арифметичні операції

До арифметичних операцій відносяться:

  •  додавання + (плюс);
  •  віднімання - (дефіс);
  •  множення * (зірочка);
  •  ділення / (похила риска — слеш);
  •  остача від ділення (ділення по модулю) % (процент);
  •  інкремент (збільшення на одиницю) ++;
  •  декремент (зменьшення на одиницю)  - -

Між спареним плюсами і мінусами не можна залишати пробіли. Додавання, віднімання і множення  цілих значень виконується як звичайно, а от ділення  цілих значень в результаті дає знову  ціле (так зване "ціле ділення"), наприклад, 5/2 дасть в результаті 2, а не 2.5, а 5/(-3) дасть -1. Дробова частина попросту відкидається, відбувається урізання частки. Це спочатку дивує, а потім виявляється зручним для урізання чисел.

Зауваження

В Java прийнято цілочисельне ділення.

Це дивне для математики правило природнє  для програмування: якщо обидва операнди мають один і той же тип, то і результат має той же тип. Досить написати 5/2.0 або 5.0/2 або 5.0/2.0 і одержимо 2.5 як результат ділення дійсних чисел.

Операція ділення по модулю визначається  так: а % b = а - (а / b) * b; наприклад, 5%2 дасть в результаті 1, а 5% (-3) дасть 2, тому що 5 = (-3) * (-1) + 2, але (-5)%3 дасть -2, оскільки -5 = 3 * (-1) - 2.

Операції інкремент і декремент означають збільшення або зменшення значення змінної  на одиницю і застосовуються тільки для змінних, а не для констант чи виразів, не можна написати 5++ або (а + b)++.

Наприклад, після приведених вище описань i++ дасть -99, a j—- дасть 99.

Цікаво, що ці операції можна записати і перед змінною: ++i, - - j. При першій формі запису (постфіксній) у виразі приймає участь старе  значення змінної і лише потім відбувається збільшення чи зменшення її значення. При другій формі запису (префіксній) спочатку зміниться змінна і її нове значення буде приймати участь у виразі.

Наприклад, після приведених вище описань, (k++) + 5 дасть в результаті 10004, а змінна k прийме значення 10000. Але в тій же  ситуації (++k) + 5 дасть 10005, а змінна k стане рівною 10000.

2.7.5.2.  Приведення типів

Результат арифметичної операції має тип int, крім того випадку, коли один із операндів єсть типу long. В цьому випадку результат буде типу long.

Перед виконанням арифметичної операції завжди відбувається підвищення (promotion) типів byte, short, char. Вони перетворюються в тип int, а може бути, і в тип long, якщо інший операнд має тип long. Операнд типу int підвищується до типу long, якщо інший операнд є типу long. Звичайно, числове значення операнда при цьому не змінюється.

Це правило приводить інколи до неочікуваних результатів. Спроба скомпілювати просту програму, представлену в лістинзі 1.3, приведе до повідомлення компілятора про помилку. Перевірте!

Лістинг 2.3. Невірне визначення змінної

class InvalidDef{

public static void main (String [] args) {

byte b1 = 50, b2 = -99;

short k = b1 + b2; // Невірно! '

System.out.println("k=" + k);

}

} 

Це повідомлення  означає, що в файлі InvalidDef.java, в рядку 4, виявлена можлива втрата точності (possible loss of precision). Потім приводиться виявлений (found) і потрібний (required) типи, виводиться рядок, в якому виявлена (а не зроблена) помилка, і відмічається символ, при аналізі якого знайдена помилка.  В кінці вказано загальне число виявлених  (а не зроблених) помилок (1 error).

В таких випадках треба виконувати явне приведення типу. В даному випадку це буде звуження (narrowing) типа int до типа short. Воно здійснюється операцією явного приведення, котра записується перед потрібним значенням у вигляді імені типа в дужках. Визначення

short k = (short)(b1 + b2);

буде вірним.

Звуження відбувається просто відкиданням  старших бітів, що необхідно враховувати для великих  значень. Наприклад, визначення

byte b = (byte) 300;

дасть змінній b значення 44. Дійсно, в двійковому представленні числа 300, рівному 100101100, відкидається старший біт і получається 00101100. Таким же чином можна привести і явне розширення (widening) типу, якщо в цьому єсть необхідність.  

Якщо результат цілої операції виходить за діапазон свого типа int або long, то автоматично відбувається приведення по модулю, рівному довжині цього  діапазона, і обчислення продовжуються, переповнення ніяк не відмічається.

Зауваження

В мові Java немає цілочисленого переповнення.

2.7.5.3. Операції порівняння

В мові Java єсть шість звичайних операцій порівняння цілих чисел по величині:

  •  більше >;
  •  менше <;
  •  більше або дорівнює >=;
  •  менше або дорівнює <=;
  •  рівно ==;
  •  не рівно !=.

Спарені символи записуються без пробілів, їх не можна переставлять місцями, запис => будет невірним. Результат порівняння — логічне значення: true, в результаті, наприклад, порівняння 3 != 5; або false, наприклад, в результаті порівняння 3 == 5.

Для запису складних порівнянь слід застосовувати логічні операції. Наприклад, в обчисленнях часто приходиться робити перевірку типу а < х < b. Подібний запис в мові Java приведе до повідомлення про помилку, оскільки перше порівняння, а < х, дасть true або false, a Java не знає, більше це, ніж b, чи менше. В даному випадку слід написати вираз (а < х) && (х < b), причому тут дужки можна опустить, написати просто а < х && х < b, але про це трохи пізніше.

2.7.5.4.  Побітові операції

Інколи приходиться змінювати значення окремих бітів в цілих даних. Це виконується за допомогою побітових (bitwise) операцій шляхом накладання маски. В мові Java єсть чотири побітові операції:

  •  доповнення (complement) ~ (тильда);
  •  побітова конюнкція (bitwise AND) &;
  •  побітова дизюнкція (bitwise OR) |;
  •  побітове виключне АБО (bitwise XOR) ^.

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

В нашому прикладі b1 == 50, двійкове представлення 00110010, b2 == -99, двійкове представлення 10011101. Перед операцією відбувається підвищення до типу int. Одержимо представлення із 32-х розрядів для b1 — 0...00110010, для b2 — 1...10011101. В результаті побітових операцій одержимо:

  •  ~b2 == 98, двійкове представлення 0...01100010;
  •  b1 & b2 == 16, двійкове представлення 0...00010000;
  •  b1 | b2 == -65, двійкове представлення 1...10111111;
  •  b1 ^ b2 == -81, двійкове представлення 1...10101111.

Двійкове представлення кожного результату займає 32 біти.

Зверніть увагу, що доповнення ~х завжди еквівалентно (-x) -1.

Таблиця 1.3. Побітові операції

nl 

n2 

~nl 

nl & n2 

nl | n2 

nl ^ n2 

1

0

0

0

1

0

0

0

0

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

2.7.5.5.  Зсуви  

В мові Java єсть три операції зсуву двійкових розрядів:

  •  зсув вліво <<;
  •  зсув вправо >>;
  •  беззнаковий зсув вправо >>>.

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

Наприклад, операція b1<< 2 зсуне вліво на 2 розряди попередньо підвищене значення 0...00110010 змінної b1, що дасть в результаті 0...011001000, десяткове 200. Звільнені справа розряди заповняються нулями, ліві розряди, що знаходяться за 32-м бітом, втрачаються.

Операція b2 << 2 зсуне  підвищене значення 1...10011101 на два розряди вліво. В результаті одержимо 1...1001110100, десяткове значення  -396.

Зверніть увагу, що зсув вліво на n розрядів еквівалентний множенню числа на 2 в степені n.

Операція b1 >> 2 дасть в результаті 0...00001100, десяткове 12, а b2 >> 2 — результат 1..11100111, десяткове -25, тобто зліва зсувається старший біт, праві біти втрачаються. Це так званий арифметичний зсув. 

Операція беззнакового зсуву у всіх випадках ставить зліва на звільнені місця нулі, здійснюючи логічний зсув. Але внаслідок попереднього підвищення це має ефект лише для декількох старших розрядів від’ємних чисел. Так, b2 >>> 2 має результатом 001...100111, десяткове число 1 073 741 799.

Якщо ж ми хочемо одержати логічний зсув початкового значення  змінної b2, тобто, 0...00100111, треба попередньо накласти на b2 маску, обнуливши старші біти: (b2 & 0XFF) >>> 2.

Зауваження 

Будьте обережні при використанні зсувів вправо. Вам зараз важко уявити, в яких програмах може знадобитися зсув. Але він досить вживаний в програмуванні. Якщо ви знайдете його у якійсь програмі, то не полініться розібратися в його механізмі і доцільності застосування.

2.7.6.  Дійсні типи

Дійсних типів у Java два: float і double. Вони характеризуються розрядністю, діапазоном значень і точністю представлення, що відповідає стандарту IEEE 754-1985 з деякими змінами. До звичайних дійсних чисел додаються ще три значення»

1. Додатня нескінченість, що виражається  константою POSITIVE_INFINITY . Вона виникає при переповненні додатнього  значення, наприклад, в результаті операції множення 3.0*6е307.

2. Відємна нескінченість NEGATIVE_INFINITY.

3. "Не число", що записується константою NaN (Not a Number). Вона виникає при діленні дійсного числа на нуль або при  множенні нуля на нескінченість.

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

Операції з нескінченістю виконуються по звичайним математичним правилам.

У всьому останньому дійсні типи — це звичайні, дійсні значення, до яких можна застосувати всі арифметичні операції і порівняння, перечислені для цілих типів. Характеристики дійсних типів приведені в табл. 1.4.

Знавцям C/C++ 

В мові Java остача від ділення %, інкремент ++ і декремент — застосовується і для дійсних чисел.

Таблиця 1.4. Дійсні типи

Тип

Розрядність

Діапазон

Точність

float

4

3,4е-38 < |х| < 3,4е38

7—8 цифр

double 

8

1,7е-308<|х|<1,7е308

17 цифр

Приклади визначення дійсних типів:

float х = 0.001, у = -34.789;

double 21 = -16.2305, z2;

Оскільки до дійсних типів застосовуються всі арифметичні операції і порівняння, цілі і дійсні  значення можна змішувати в операціях. При цьому правило приведення типів доповнюється такими умовами:

  •  якщо в операції один операнд має тип double, то і другий приводиться до типу double;
  •  якщо один операнд має тип float, то і другий приводиться до типу float;
  •  в противному випадку діє правило приведення цілих значень.

2.7.7.  Операції присвоювання

Просто операція присвоєння (simple assignment operator) записується знаком рівності =, зліва від котрого стоїть змінна, а справа вираз, сумісний з типом змінної: х = 3.5, у = 2 * (х - 0.567) / (х + 2), b = х < у, bb = х >= у && b.

Операція присвоювання діє так: вираз, що стоїть після знака рівності, обчислюється і приводиться до типу змінної, що стоїть зліва від знака рівності. Результатом операції буде приведене значення правої частини.

Операція присвоювання має ще одну, побічну, дію: змінна, що стоїть зліва, одержує приведене значення правої частини, старе її значення втрачається.

В операції присвоювання ліва і права частини нерівноправні, не можна написати 3.5 = х. Після операції х = у зміниться змінна х, ставши рівною у, а після у = х зміниться у.

Крім простої операції присвоювання єсть ще 11 складних операцій присвоювання (compound assignment operators): +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=; >>>=. Символи записуються без пробілів, не можна переставляти їх місцями.

Всі складні операції присвоювання діють по одній схемі:

х ор= а еквівалентно х = (тип х), тобто (х ор а).

Нагадаємо, що змінна ind типу short визначена у нас із значенням 1. Присвоювання ind +=7.8 дасть в результаті число 8, те ж саме значення одержить і змінна ind. Ця операція еквівалентна простій операції присвоювання ind = (short)(ind + 7.8).

Перед присвоюванням, при необхідності, автоматично відбувається приведення типу. Тому:

byte b = 1;

b = b + 10; // Помилка!

b += 10; // Правильно!

Перед додаванням  b + 10 відбувається підвищення b  до типа int, результат додавання теж буде тип int і, в першому випадку  не може бути присвоєний змінній  b без явного приведення типа. В другому випадку перед присвоюванням відбудеться звуження результату додавання до типу byte.

2.7.8. Умовна операція

Ця своєрідна операція має три операнди. Спочатку записується довільний логічний вираз, тобто такий, що має результатом true або false, потім ставиться  знак питання, потім два довільних вирази, розділених  двокрапкою, наприклад,

х < 0 ? 0 : х

х > у ? х - у : х + у

Умовна операція виконується так. Спочатку обчислюється логічний вирз. Якщо одежано значення true, то обчислюється перший вираз після  знака ? і його значення буде результатом всієї операції. Останній вираз при цьому не обчислюється. Якщо  ж отримане значення false, то обчислюється тільки останній вираз, його значення буде результатом операції.

Це  дозволяє написати n == 0 ?  : m / n не боячись ділення на нуль. Умовна операція спочатку здається дивною, але вона дуже зручна для  запису невеликих розгалужень.

2.8.  Вирази

Із констант і змінних , операцій над ними, викликів методів і дужок складаються вирази (expressions). Розуміється, всі елементи виразу повинні бути сумісними, не можна написати, наприклад, 2 + true. При обчисленні виразу виконуються чотири правила:

1. Операції одного пріоритету обчислюються зліва направо: х + у + z обчислюється як (х + у) + z. Виняток: операції присвоювання виконуються справа наліво: х = у = z обчислюється як х = (у = z).

2. Лівий операнд обчислюється раніше правого.

3. Операнди повністю обчислююються перед виконанням операції.

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

Наступні приклади показують особливості застосування перших трьох правил. Нехай

int а = 3, b = 5; 

Тоді результатом виразу b + (b = 3) буде число 8; але результатом виразу (b = 3) + b будет число 6. Вираз b += (b = 3) дасть в результаті 8, тому що обчислюється як перший із наведених вище виразів.

Знавцям C/C++ 

Більшість компіляторів мови C++ у всіх цих випадках вичислять значення 8.

Четверте правило можна продемонструвати так. При тих же визначеннях а і в результаті обчислення виразу  b+= а += b += 7 одержимо 20. Хоча операції присвоювання виконується справа наліво і після першої, правої, операції значення b становиться рівним 12, але в останньому, лівому, присвоюванні приймає участь  старе значення b , рівне 5. А в результаті двох послідовних обчислень а += b += 7; b += а; одержимо 27, оскільки в другому виразі приймає участь уже нове значення змінної  b, рівне 12.

Знавцям C/C++ 

Більшість компіляторів C++ в обох випадках  обчислять 27.

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

Решта  правил перечислені в наступному розділі.

Порядок обчислення виразу завжди можна відрегулювати дужками, їх можна ставити скільки завгодно. Але тут  важливо зберігати "золоту середину". При великій кількості дужок знижується наочність виразу і легко помилитися в розстановці дужок. Якщо вираз з дужками корректний, то компілятор може відслідкувати тільки парність дужок, але не правильність їх розстановки.

2.9.  Пріоритет операцій

Операції перечислні в порядку спадання пріоритета. Операції в одному рядку мають однаковий пріоритет.

1. Постфіксні операції ++ і  - -  

2. Префіксні операції ++ і - -, доповнення ~ і заперечення !.

3. Приведення типу (тип).

4. Множення *, ділення / і знаходження решти %.

5. Додавання + і віднімання -.

6. Здвиги <<, >>, >>>.

7. Порівняння >, <, >=, <=.

8. Порівняння ==, !=.

9. Побітова конюнкція &.

10. Побітове виключне АБО ^.

11. Побітова дизюнкція | .

12. Конюнкція &&.

13. Дизюнкція | | .

14. Умовна операція ?: .

15. Присвоювання =, +=, -=, *=, /=, %=, &=, ^=, |=, <<, >>, >>>.

Тут перечислені не всі операції мови Java, список буде доповнюватися по мірі вивчення нових операцій.

2.10.  Оператори

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

Записати його можна в різних формах: у вигляді блок-схеми, на псевдокоді, на звичайній мові, як ми записуємо кулінарні рецепти, або як-небудь ще .

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

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

Набір операторів мови Java включає:

  •  оператори описування змінних і інших обєктів (вони були розглянуті вище);
  •  оператори-вирази;
  •  оператори присвоювання;
  •  умовний оператор if;
  •  три оператори циклу while, do-while, for;
  •  оператор варіанта switch;
  •  Оператори переходу break, continue і return; 
  •  блок {};
  •  пустий оператор — просто крапка з комою.

Тут приведений не весь набір операторів Java, він буде доповнюватися по мірі вивчення мови.

Зауваження 

В мові Java немає оператора goto.

Всякий оператор закінчується крапкою з комою.

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

Знавцям Pascal 

Крапка з комою в Java не розділяє оператори, а являється частиною оператора.

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

2.10.1.  Блок

Блок заключає в собі нуль або декілька операторів з метою використовувати їх як один оператор в тих місцях, де по правилах мови можна записати тільки один оператор. Наприклад, {х = 5; у = ?;}. Можна записати і пустий блок, просто пару фігурних дужок {}.

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

2.10.2.  Оператори присвоювання

Крапка з комою в кінці будь-якої операції присвоювання перетворює її в оператор присвоювання. Побічна дія операції — присвоювання — становиться в операторі основним.

Різниця між операцією і оператором присвоювання носить лише теоретичний характер. Присвоювання частіше застосовується як оператор, а не як операція.

2.10.3.  Умовний оператор

Умовний оператор (if-then-else statement) у мові Java записується так:

if (логічний вираз) оператор1 else оператор2

і діє наступним чином. Спочатку обчислюється логічний вираз. Якщо результат true, то діє оператор1 і на цьому дія умовного оператора завершуєтсья, оператор2 не діє, далі буде виконуватися наступний за if оператор. Якщо результат false, то діє оператор2, при цьому оператор1 взагалі не виконується.

Умовний оператор може бути скороченим (if-then statement):

if (логвир) оператор1

і у випадку  false не виконується нічого.

Синтаксис мови не дозволяє записувати декілька операторів ні у гілці then, ні у гілці else. При необхідності створюється блок операторів у фігурных дужках.  "Code Conventions" рекомендує завжди використовувати фігурні дужки і розташовувати оператор в декількох рядках з відтступами, як в наступному прикладі:

if (а < х) {

х = а + b; } else {

х = а - b;

}

Це полегшує додавання оператороі в кожну гілку при зміні алгоритма. Ми не будемо строго слідувати цьому правилу, щоб не збільшувати розмір тексту.

Дуже часто одним із операторів являється знову умовний оператор, наприклад:

if (n == 0) {

sign = 0;

} else if (n < 0) {

sign = -1;

} else {

sign = 1;

} 

При цьому може виникнути така ситуація ("dangling else"):

int ind = 5, х = 100;

if (ind >= 10) if (ind <= 20) x = 0; else x = 1;

Збереже змінна х значення 100 чи стане рівною 1? Тут необхідно вольове рішення, і спільне  для більшості мов, в тому числі і Java. Правило таке: гілка else відноситься до найближчої зліва умови if, що не має своєї гілки else. Тому в нашому прикладі змінна х залишиться рівною 100.

Змінити цей порядок можна за допомогою блоку:

if (ind > 10) {if (ind < 20) x = 0; else x = 1;}

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

if (ind >= 10 && ind <= 20) х = 0; else х = 1;

Користуйтеся тим, що ви узнали про пропозиції в Дискретній Математиці. Одну з них можна замінити на еквівалентну, більш простішу для розуміння.

В лістинзі 1.4 обчислюються корені квадратного рівняння ах2 + bх + с = 0 для любих коэфіцієнтів, в тому числі і нульових.

Лістинг 2.4. Обчислення коренів квадратного рівняння 

class QuadraticEquation{

public static void main(String[] args){

double a = 0.5, b = -2.7, с = 3.5, d, eps=1e-8;

if (Math.abs(a) < eps)

if (Math.abs(b) < eps)

if (Math.abs(c) < eps) // Всі коефіцієнти рівні нулю

System.out.println("Розвязок —будь-яке число");

else

System.out.println("Розвязків немає");

else

System.out.println("xl = x2 = " +(-c / b) ) ;

else { // Коэфіцієнти не рівні нулю

if((d = b**b - 4*a*c)< 0.0){ // Комплексні корені

d = 0.5 * Math.sqrt(-d) / a;

a = -0.5 * b/ a;

System.out.println("xl = " +a+ " +i " +d+

",x2 = " +a+ " -i " +d);

} else {

// Дійсні корені

d =0.5 * Math.sqrt(d) / a;

a = -0.5 * b / a;

System.out.println("x1 = " + (a + d) + ", x2 = " +(a - d));

}

}

}

}

В цій програмі використані методи обчислення модуля abs() і квадратного кореня sqrt() з дійсного числа із вбудованого в Java API класу Math. Оскільки всі обчислення з дійсними числами виконуються наближено, ми вважаємо, що коефіцієнт рівняння дорівнює нулю, якщо його модуль менше 0,00000001. Зверніть увагу  на те, як в методе println() використовується зєднання рядків, і на те, як операція присвоювання при обчисленні дискримінанта вкладена в логічний вираз. Прослідкуйте складну ієрархію операторів if ... else. Якщо це вам здасться дуже заплутаним, переробіть програму використовуючи логічнні функції.

"Продвинутим" користувачам 

Вам уже хочеться вводити коэфіцієнт а, b і с прямо з клавіатури? Будь ласка, користуйтеся методом System. in. read (byte [ ] bt), але майте на увазі, що цей метод записуєт введені цифри в масив байтів bt в кодуванні ASCII, в кожний байт по одній цифрі. Масив байтів потім треба перетворити в дійсне число, наприклад, методом Double(new String(bt)).doubleValue() . Незрозуміло? Але це ще не все, треба опрацювати виключні ситуації, які можуть виникнути при введенні. Пізніше, можливо, ми розглянемо це питання більш детально.

2.10.4.  Оператори циклу

2.10.4.1.  Оператор while

Основний оператор циклу — оператор while — виглядає так:

while (логвир) оператор

Спочатку обчислюється  логічний вираз логвир; якщо його значення true, то виконується  оператор, що утворює цикл. Потім знову обчислюється логвир і діє оператор, і так до тих пір, поки не получиться значення false. Якщо логвир з самого початку рівний false, то оператор не буде виконуватися ні разу. Попередня перевірка забезпечує безпеку виконанняя циклу, дозволяє уникнути переповнення, ділення на нуль і інші неприємності. Тому оператор while являеться основним, а в деяких мовах і єдиним оператором циклу.

Оператор в циклі може бути і пустим, наприклад, наступний фрагмент коду:

int i = 0;

double s = 0.0;

while ((s += 1.0 / ++i) < 10);

обчислює суму членів гармонічного ряду до тих пір, поки вона досягне значення 10.  Такий стиль характерний для мови С. Не варто ним захоплюватися, щоб не перетворити текст програми в шифровку, на яку ви самі через пару тижнів будете дивитися зі здивуванням.

Можна організувати і нескінчений цикл:

while (true) оператор 

Звичайно, із такого циклу треба передбачити якийсь вихід, наприклад, оператором break, як в лістинзі 1.5. В противному випадку програма зациклиться, і вам прийдеться закінчувати її виконання  "комбінацією з трьох пальців" <Ctrl>+<Alt>+<Del> у MS Windows 95/98/ME, або через Task Manager у Windows NT/2000.

Якщо в цикл треба включить декілька операторів, то слід створити блок операторів {}.

2.10.4.2.  Оператор do-while

Другий оператор цикла — оператор do-while — має вигляд do оператор while (логвир) 

Тут спочатку виконується оператор, а потім відбувається обчислення  логічного виразу логвир. Цикл виконується, поки логвир залишається рівним true.

Знавцям Pascal 

В циклі do-while перевіряються умови продовження, а не закінчення циклу.

Суттєва різниця між цими двома операторами циклу тільки в тому, що в циклі do-while оператор обовязково виконується хоча б один раз.

Наприклад, нехай задана якась функція f(x), що має на відрізку [0; b] рівно один корінь. В лістинзі 1.5 приведена програма, що обчислює цей корінь наближено методом ділення пополам (бісекції, дихотомії).

Лістинг 2.5. Знаходження кореня нелінійного рівняння методом бісекції

class Bisection {

static double f(double x){

return x*x*x - 3*x*x +3; // Або щось інше

}

public static void main(String[] args){

double a = 0.0, b = 1.5, c, y, eps = 1e-8;

do{

c = 0.5 *(a + b); y = f(c);

if (Math.abs(y) < eps) break;

// Корінь знайдено. Виходимо із циклу

//Якщо на кінцях відрізка [а; c]  функція має різні знаки:

if (f (a) * y < 0.0) b = c;

// Значить, корінь тут. Переносимо точку b в точку c

//В противному випадку:

else a = c;

// Переносимо точку а в точку с

// Продовжуємо, доки відрізок [а; b] не стане малим

} while (Math. abs (b -a) >= eps);

System.out.println("x = " +c+ ", f(" +c+ ") = " +y) ;

}

}

Клас Bisection складніший за попередні приклади: в ньому крім метода main () єсть іще метод обчисленя функції f(x). Тут метод f() дуже простий: він обчислює значення многочлена і повертає його в якості значення функції, причому все це виконується одним оператором:

return вираз 

В методі main() появився ще один новий оператор break, який просто закінчує виконання циклe, якщо ми по щасливій випадковості наткнулися на наближене значення кореня. Уважний читач помітив і появу модифікатора static в оголошенні метода f(). Він необхідний тому, що метод f() викликється із статичнго метода main().

2.10.4.3.  Оператор for

Третій оператор циклe — оператор for — виглядає так:

for (списокВир1; логВир; списокВир2) оператор 

Перед виконанням циклу обчислюється список виразів списокВир1. Це нуль або декілька виразів, перечислених через кому. Вони обчислюються зліва направо, і в наступному виразі уже можна використовувати результат попереднього виразу. Як правило, тут задаються початкові значення змінних циклe.

Потім обчислюється логічний вираз  логвир. Якщо він істинний, true, то діє оператор, потім обчислюється зліва направо вирази із списку виразів списокВир2. Далі знову перевіряється логвир. Якщо він  істинний, то виконується оператор і списокВир2 і т. д. Як тільки логвир стане рівним false, виконання циклу закінчується.

Коротше кажучи, виконується послідовність операторів

списокВир1; while (логВир){ 

оператор 

списокВир2; } 

з тим виключенням, що, коли оператором в циклі являється оператор continue, то списокВир2 все-таки виконується.

Замість списокВир1 може стояти одне визначення змінних обовязково з початковим значенням. Такі змінні діють лише в межах цього цикла.

Будь-яка частина оператора for може бути відсутня: цикл може бути пустим, вираз в заголовку теж, при цьому крапки з комою зберігаються. Можна задати нескінчений цикл:

for (;;) оператор

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

Хоча в операторі for закладені великі можливості, використовується він, головним чином, для  перечислень, коли їх число відомо, наприклад, фрагмент коду ,

int s=0;

for (int k = 1; k <= N; k++) s += k * k;

// Тут змінна k вже невідома

обчислює суму квадратів перших N натуральних чисел.

2.10.5.  Оператор continue і мітки

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

for (int i = 0; i < N; i++){

if (i == j) continue;

s += 1.0 / (i - j);

}

 

Друга форма містить мітку:

continue мітка

мітка записується, як і всі  ідентифікатори, із літер Java, цифр і знака підкреслювання, але не вимагає ніякого описання. Мітка ставиться перед оператором або відкриваючій фігурній дужці і відокремлюється від них двокрапкою. Так виходить помічений оператор або помічений блок. 

Знавцям Pascal 

Мітка не вимагає описання і не може починатися з цифри.

Друга форма використовується тільки у випадку декількох вкладених циклів для негайного переходу до чергової ітерації одного із зовнішніх циклів, а саме, поміченого цикла.

2.10.6. Оператор break

Оператор break використовується в операторах циклу і операторі варіанта для негайного виходу із цих конструкцій.

Оператор break мітка 

Наступна схема пояснює цю конструкцію.

Ml: { // Зовнішній блок

М2: { // Вкладений блок — другий рівень

М3: { // Третій рівень вкладеності...

if (щось трапилось) break M2;

// Якщо true, то тут нічого не виконується

}

// Тут теж нічого не виконується

}

// Сюди передається управління

}

Спочатку збиває в пантелику та обставина, що мітка ставиться перед блоком або оператором, а управління передається за цей блок або оператор. Тому не варто захоплюватися оператором break з міткою.

2.10.7. Оператор варіанта

Оператор варіанта switch організує розгалуження по декількох напрямках. Кожна гілка відмічається константою або константним виразом якого-небудь цілого типа (крім long) і вибирається, якщо значення певного виразу співпадає з цією константою. Вся конструкція виглядає так.

switch (цілВир){

case констВир1: оператор1

case констВир2: оператор2

. . . . .

case констВирN: операторN

default: операторDef

}

Вираз в дужках  цілвир може бути типу byte, short, int, char, але не long. Цілі числа або цілочисельні вирази, складені із констант, констВир теж не повинні мати тип long.

Оператор варіанта виконується так. Всі константні вирази обчислюються заздалегідь, на етапі компіляції, і повинні мати відмінні один від одного значения. Спочатку обчислюються цілочисельний вираз цілвир. Якщо він співпадає з однією із констант, то виконується оператор, помічений цією константою. Потім виконуються ("fall through labels") всі наступні оператори, включаючи і операторDef, і робота оператора варіант закінчується.

Якщо ж жодна константа не рівна значенню виразу, то виконується операторDef і всі наступні оператори. Тому гілка default повинна записуватися останньою. Гілка default може бути відсутня, тоді в цій ситуації оператор варіанта взагалі нічого не робить.

Таким чином, константи у варіантах case грають роль тільки міток, точок входу в оператор варіанта, а далі виконуються всі інші оператори в порядку їх запису.

Знавцям Pascal 

Після виконання одного варіанта оператор switch продовжує виконувати всі інші варіанти.

Частіше всього необхідно "пройти" тільки одну гілку операторів. В такому випадку використовується оператор break, який зразу ж зупиняє виконання оператора switch. Може знадобитися виконати один і той же оператор в різних гілках case. В цьому випадку ставимо декілька міток case підряд. Ось простий приклад.

switch(dayOfWeek){

case 1: case 2: case 3: case 4:case 5:

System.out.println("Week-day");, break;

case 6: case 7:

System.out.println("Week-end"); break;

default:

System.out.printlnt("Unknown day");

}

Зауваження 

He забувайте завершати варіанти оператором break.

2.11.  Масиви

Як завжди в програмуванні массив — це сукупність змінних одного типу, що зберігаються в суміжних комірках оперативної пам’яті.

Масиви в мові Java відносяться до посилкових типів і описуються своєрідно, але характерно для посилкових типів. Описання проходить в три етапи.

Перший етап — оголошення (declaration). На цьому етапі визначається тільки змінна типу посилання (reference) на масив, і містить тип масиву. Для цього записується ім’я типу елементів масиву, квадратними дужками указується, що оголошується посилання на масив, а не проста змінна, і перечислюються імена змінних типу посилання, наприклад,

double[] а, b;

Тут визначені дві змінні — посилання а і b на масиви типа double. Можна поставити квадратні дужки і безпосередньо після імені. Це зручно робити серед визначень звичайних змінних:

int I = 0, ar[], k = -1;

Тут визначені дві змінні цілого типа i і k, і оголошено посилання на цілочисельний масив аг.

Другий етап — визначення (installation). На цьому етапі указується кількість елементів масиву, це називається його довжиною, виділяється місце для масиву в оперативній пам’яті, змінна-посилання одержує адресу масиву. Всі ці дії виконуються ще однією операцією мови Java — операцією new тип, що виділяє місце в оперативній пам’яті для об’єкта указаного в операції типу і повертає в якості результату адресу цього місця. Наприклад,

а = new double[5];

b = new double[100];

ar = new int[50];

Індекси масивів завжди починаються з 0. Масив а складається із пяти зміних а[0], а[1], , а[4]. Елемента а[5] в масиві немає. Індекси можна задавати любими цілочисельними виразами, крім типа long, наприклад, a[i+j], a[i%5], a[++i]. Виконуюча система Java слідкує за тим, щоб значення цих виразів не виходили за межі довжини масива.

Третій етап — ініціалізація (initialization). На цьому етапі елементи масиву отримують початкові значення. Наприклад,

а[0] = 0.01; а[1] = -3.4; а[2] = 2:.89; а[3] = 4.5; а[4] = -6.7;

for (int i = 0; i < 100; i++) b[i] = 1.0 /i;

for (int i = 0; i < 50; i++) ar[i] = 2 * i + 1;

Перші два етапи можна сумістити:

a = new double[5], b = new double[100]; 

int i = 0, ar[] = new int[50], k = -1;

Можна зразу задати і початкові значення, записавши їх в фігурних дужках через кому у вигляді констант або константних виразів. При цьому навіть необов’язково указувати кількість елементів масиву, вона буде рівною кількості початкових значень;

double[] а = {0.01, -3.4, 2.89, 4.5, -6.7};

Можна сумістити другий і третій етап:

а = new double[] {0.1, 0.2, -0.3, 0.45, -0.02};

Можна навіть створити безіменний масив, зразу ж використовуючи результат операції new, наприклад, так:

System.out.println(new char[] {'H', 'e', '1', '1', 'o'});

Посилання на масив не являється частиною описаного масива, її можна перекинуть на другий масив того ж типу операцією присвоювання. Наприклад, після присвоювання а = b обидві посилки а і b указують на один і той же масив із 100 дійсних змінних  типу double і містять одну і ту  ж адресу.

Посилання може присвоїти "пусте" значення null, що не указує на жодну адресу оперативної памяті:

ar = null;

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

Крім  простої операції присвоювання, з посиланнями можна виконувати ще тільки порівняння на рівність, наприклад, а = b, і нерівність, а != b. При цьому співставляються адреси, що містяться в посиланнях, ми можемо взнати, чи не посилаються вони на один и той же масив.

Зауваження для спеціалістів 

Масиви в Java завжди визначаються динамічно, хоча посилання на них задаються статично.

Крім посилання на масив, для кожного масиву автоматично визначається ціла константа з одним і тим же іменем length. Вона рівна довжині масива. Для кожного масиву імя цієї константи уточнюється іменем масиву через точку. Так, після наших визначень, константа a.length рівна 5, константа b. length рівна 100, a ar. length рівна 50.

Останній елемент масиву а можна записати так: a [a. length - 1], передостанній — a [a. length - 2] і т. д. Елементи масиву звичайно перебираються в циклі виду:

double aMin = a[0], aMax = aMin;

for (int i = 1; i < a.length; i++){

if <a[i] < aMin) aMin = a[i];

if (a[i] > aMax) aMax = a[i];

}

double range = aMax - aMin;

Тут обчислюється діапазон значень масиву.

Елементи масиву — це звичайні змінні свого типу, з ними можна виконувати всі операції, допустимі для цього типу:

(а[2] + а[4]) / а[0] і т. д.

Знавцям C/C++ 

Масив символів в Java не являється рядком, навіть якщо він закінчується нуль-символом ' \u0000'.

2.12.  Багатовимірні масиви

Елементами масиву у Java можуть бути знову масиви. Можна оголосити:

char[] [] с;

що еквівалентно

chart[] с[];

або

char с[][];

Потім визначаємо зовнішній масив:

с = new char[3][];

Становиться ясно, що с — масив, який складається з трьох элементів-масивів. Тепер визначимо його елементи-масиви:

с[0] = new char[2];

с[1] = new char[4];

с[2] = new char[3];

Після цих визначень змінна с.length рівна 3, с[0] .length рівна 2,

c[l].length рівна 4 і с[2].length рівна 3.

Нарешті, задаємо початкові значення с [0] [0] = 'a', с[0][1] = 'r',

с[1][0] = 'г',с[1][1] = 'а',с[1][2] = 'у' і т.д.

Зауваження 

Двомірний масив у Java не зобов’язаний бути прямокутним.

Описування можна скоротити:

int[] [] d = new int[3] [4];

А початкові значення задати так:

int[] []  d = {{I, 2, 3}, {4, 5, 6}};

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

Лістинг 2.6. Трикутник Паскаля

class PascalTriangle{

public static final int LINES = 10; // Так визначаються константи

public static void main(String[] args) {

int[][] p = new int [LINES] [];

p[0] = new int[1];

System. out. println (p [0] [0] = 1);

p[1] = new int[2];

p[1][0] = p[1][1] = 1;

System.out.println(p[1][0] + " " + p[1][1]);

for (int i = 2; i < LINES; i++){

p[i] = new int[i+1];

System.out.print((p[i][0] = 1) + " ");

for (int j = 1; j < i; j++)

System.out. print ( (p[i] [j] =p[i -1][j -1] + p[i-1][j]) + " ");

System. out. println (p [ i] [i] = 1);

}

}

}

Заключення

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

Лабораторна робота 1. Базові поняття Java

1. Підготуйте простенькі програми для ілюстрації елементів мови Java розглянутих в пунктах

2.5.1

2.5.3

2.5.4

2.6

2.7.2

2.7.3

2.7.4

2.7.5.1

2.7.5.2

2.7.5.3

2.7.5.4

2.7.5.5

2.7.6

2.7.7

2.7.8

2.8

2.9

2.10.1

2.10.2

2.10.3

2.10.4.1

2.10.4.2

2.10.4.3

2.10.5

2.10.6

2.10.7

2.11

2.12

Памятайте, завдання вважається виконаним, якщо програма спрацювала так, як ви того і хотіли. А те що ви хотіли від програми, повинно бути записане в коментарі на початку програми. Тут же вкажете і своє прізвище. Скопіюйте текст програми у doc файл і туди ж скопіюйте вікно  Командная строка з результатом виконання програми. Розподіліть самостійно програми між собою. Назвіть файл відповідним пунктом, за яким повинно слідувати ваше прізвище, наприклад 21041_Popov. Ці файли здати старостам, які обєднають їх у папку Java2Lab і передадуть викладачу.

Деякі з цих програм ви поясните всім на лекціях, деякі продемонструєте в лабораторії.

2. Ознайомтеся з методами класів System  і Character по відповідним файлам. Звертайтесь до цих файлів кожен раз, коли треба зрозуміти, як працює той чи інший метод .




1. Гибель клеток головного мозга которые отмирая попадают в кровь отфильтровываются почками и выходят с моч
2. 1 Устройства и системы предотвращения угонов и посягательств на автомобиль Проблема охраны автомобилей
3. Тема5 1Просвещение это идейное и общественное движение в Европе и Северной Америке конца XVII XVIII вв
4. 6094 Перед назначением ответственными лицами за исправное состояние и безопасную эксплуатацию паровых
5. Европа Когда я жил в СССР Где пионер всем был пример И Ленин вместо бога был А Брежнев сказки говорил
6. Тематика дисципліни Теорія організації Тема 1
7. МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ УШИБЫ ВЫВИХИ ПЕРЕЛОМЫ.html
8. Реферат- Обучаемая система поддержки коллективного решения группы независимых экспертов
9. 10 стор. м-п тексту повинен складатися з підрозділів- вступ; аналіз будівельнопланіровочних особлив
10. Приватизація як засіб припинення державної власності