Доброго дня. В даній статті Я в загальному розкажу про мову програмування Java. Хоча, як на мене, Java виходить за рамки мови програмування, оскільки для належного функціонування системи Java в цілому, Вам знадобляться не тільки знання мови, а й компілятор Java, інтерпретатор байткоду і Java-машина (JVM) встановлена на цільовій ЕОМ. Увесь комплекс програм можна завантажити на офіційному сайті компанії Oracle за адресою https://www.oracle.com/java/index.html. Дана стаття підійде тим, хто бажає в найкоротші терміни дізнатись про основні аспекти мови Java.

Де писати код?

Не вдаючись на даний момент в деталі, код потрібно писати між фігурними дужками на місці коментаря:
class MainClass
{
  public static void main (String[] opts)
  {
	// Java код писати сюди!
  }
}
Дану програму потрібно зберегти в файл під назвою “MainClass.java” у вигляді звичайного текстового файлу. В даному файлі також можуть розміщатись і інші класи, про які буде розповідатись далі у статті. Компілювати даний код можна за допомогою використання наступних команд:
javac MainClass.java
jar cfe test.jar MainClass *.class
Перша з яких, компілює код у файлі “MainClass.java” у байткод і поміщає результат у файл “MainClass.class”. Наступна команда збирає усі файли з розширенням “.class” у файл-пакет Java програми. Розглянемо програму “Привіт, Світ!”:
class HalloWorld
{
    public static void main (String[] argv)
    {
        System.out.println ("Привіт, Світ!") ;
    }
}
Компілювання і запуск в терміналі: java_hallo_worlds

Коментарі

У Java є два типи коментарів:
// це коментар до кінця поточного рядка

/* 
    це 
    багаторядковий 
    коментар
*/
Не забувайте коментувати — це полегшить Вам читання коду в майбутньому.

Типи даних і змінні

Система Java відноситься до строго типізованих мов програмування. Це означає, що змінна, яку ви створили в програмі, може мати тільки один тип даних. У Java є наступні типи даних:
  • числові типи
    • byte (8 біт) містить цілі числа в діапазоні від -128 до 127;
    • short (16 біт) містить цілі числа в діапазоні від -32768 до 32767;
    • int (32 розряди) містить цілі числа в діапазоні від -2147483648 до 2147483647;
    • long (64 біти) потужність типу 1,844674407×10¹⁹ цілочисельних значень (від -9223372036854775808 до 9223372036854775807)
    • float (32 біти) містить дійсні числа по абсолютній величині починаючи від 3,4 ∙ 10-38 до 3,4 ∙ 1038
    • double (64 біти) містить дійсні числа, які по абсолютній величині містяться в діапазоні від 1,7 ∙ 10-308 до 1,7 ∙ 10308.
  • символьний тип char (16 бітів), який може містити значення від 0 до 65536 (на кожен символ по значенню);
  • булевий тип — boolean (true або false).
Усі типи мають відповідний клас-обгортку, у разі, якщо необхідно звертатись до типу, як до об'єкта. В Java є тип void, який використовується для оголошення функцій, які не повертають значення. Також кожний рядок символів у Java інтерпертується як примірник вбудованого класу String. Особливість класу String полягає у тому, що після створення його вміст не можна змінити. При виконанні операцій над даними, слід пам'ятати, що існують специфічні правила приведення типів у системі Java:
  • типи змінних, які містяться у виразі, повинні бути сумісними, наприклад, цілі числа можна приводити до дійсних, окрім рядків символів;
  • тип змінної, до якого приводиться значення виразу повинно бути ширшим (по потужності типу), тобто перетворення повинні виконуватись без втрати даних;
  • перед виконанням арифметичних операцій типи byte, short і char приводяться до типу int; якщо у виразі міститься потужніший по кількості значень тип, або дійсний (long, float, double), в такому разі вираз приводиться до даного типу;
  • також у виразах літерали, які означають числа, приводяться до типу int, а літерали, які позначають дійсні числа — приводяться до double.
Декілька прикладів оголошення і ініціалізації змінних:
    int a = 10 ; 
    byte b = 127 ; 
    double r = 3.1415 ;
    char c = 'А' ; 
    String str = "Вивчаємо Джава!" ;
При необхідності, з будь-яких типів, вбудованих чи створених користувачем, можливо створити змінну масив певного типу, для зберігання групи значень даного типу. Індексація у масивах цілочисельна. Синтаксис оголошення змінної одновимірного масиву наступний:
тип [] = new тип [кількість комірок] ;
Для збільшення вимірності масиву, потрібно скористатись додатковими парами квадратних дужок, для кожного виміру. Наприклад, для створення і ініціювання двовимірного цілочисельного масиву, можна скористатись наступним кодом:
int[][] iArray = new int [][] {{1, 2, 3}, {5, 7, 11}} ;
Даний код створює і ініціює двовимірний масив з ім'ям iArray розміром 2 на 3.

Оператори

Оператори в Java можна розділити на чотири типи: арифметичні, логічні, оператори порівняння і побітові. Математичні оператори:
  • + і += - сума операндів;
  • - і -= - різниця операндів;
  • * і *= - множення операндів;
  • / i /= - ділення лівого операнда на правий;
  • % і %= - остача від ділення лівого операнда на правий;
  • ++ - постінкремент і суфіксінкремент;
  • -- -- - постдекремент і суфіксдекремент.
Дані оператори мають деякі особливості. Наприклад, якщо передати оператору ділення цілі числа, в якості результату отримаємо ціле число, тому що інтерпретатор приведе результат до того типу, який являвся у операндах — int. Тому вираз
double a = 5/2 ; /* змінна а містить значення 2,0 */
буде містити двійку замість очікуваного 2,5. Щоб отримати результат з мантисою необхідно явно привести тип:
double a = (double) 5/2 ; /* тепер змінна a містить значення 2,5 */
Оператори інкременту і декременту збільшують і зменшують значення змінної відповідно. Їх можна використовувати в двох формах суфіксній і префіксній (оператори ставляться перед змінною і після). Їх різниця полягає в тому, що при суфіксному запису спочатку повертається значення змінної, а потім виконується її інкремент/декремент; при префіксній спочатку виконується інкремент/декремент над змінною, після чого повертається нове значення. Логічні оператори:
  • && - логічне І, повертає true, тільки якщо обидва операнди маються значення true, якщо перший операнд має значення false, другий не перевіряється;
  • || - логічне АБО, повертає true, якщо хоча б один операнд має значення true, якщо обидва мають значення false — повертає false;
  • ^ - виключне АБО, повертає значення true, якщо значення обох операндів не однакові, і повертає false, якщо значення обох операндів одночасно рівне true або одночасно рівне false;
  • ! - логічне заперечення, унарний оператор, повертає значення обернене від значення операнда (!true - результат false).
Оператори порівняння значень:
  • == - перевірка рівності операндів, повертає true, якщо значення операндів рівні;
  • < - оператор перевірки меншості значення лівого операнда відносно значення правого операнда, повертає true якщо значення лівого операнда менше за значення правого;
  • <= - оператор перевірки меншості або рівності значення лівого операнда відносно правого.
  • > - оператор перевірки більшості значення лівого операнда відносно правого.
  • >= - даний оператор повертає true, якщо значення лівого операнда більше або рівне значенню правого операнда.
Побітові оператори:
  • & і &= - побітове І, дана операція застосовується до кожного біта операнда окремо, результат обчислення такий ж як у оператора &&;
  • | і |= - побітове АБО, даний оператор виконує функцію АБО окремо, для кожного біта операндів;
  • >> i >>= - повертає значення зміщеного порядку бітів лівого операнда вправо, на вказану кількість позицій в значенні правого операнда;
  • < i <<= - повертає значення зміщеного порядку бітів лівого операнда вліво, на вказану кількість позицій в значенні правого операнда;
  • >>> і >>>= - повертає значення беззнакового зміщення бітів лівого операнда вправо, на вказану кількість позицій в значенні правого операнда;
Усі оператори мають деякий пріоритет відносно один-одного. Наступний список показує оператори від найвищого пріоритету, до найнижчого:
  1. оператори дужок “()”, “[]” і оператор “крапка” (доступ до елементів класу);
  2. інкремент “++” і декремент “-- --”;
  3. оператори множення “*”, ділення “/” і оператор обрахунку остачі “%”;
  4. додавання “+” і віднімання “-”;
  5. побітові зміщення “>>”, “<<”, “>>>”;
  6. оператори перевірки відношення “>”, “>=”, “<=”, “<”;
  7. перевірка рівності “==” і “!=”;
  8. побітове І “&”;
  9. побітове АБО “|”;
  10. логічне І “&&”;
  11. логічне АБО “||”;
  12. тернарний оператор “?:”;
  13. присвоєння значення і скорочені записи операторів вигляду “оп=” (“*=”, “/=” і інші).

Оператори вибору

Оператор вибірки дозволяє обрати команди для виконання, виходячи з значень деяких умов. Він має наступний вигляд:
if ( /* умова перевірки 1 */ )
{
	/* оператори, які виконуються при 
	** дійсності умови 1 */
}
або
if ( /* умова перевірки 1 */ )
{
	/* оператори, які виконуються при 
	** дійсності умови 1 */
}
else
{
	/* оператори, які виконуються при 
	** не дійсності умови 1 */
}
Оператор вибірки з множинними умовами:
if ( /* умова перевірки 1 */ )
{
	/* оператори, які виконуються при 
	** дійсності умови 1 */
}
else if ( /* умова перевірки 2 */ )
{
	/* оператори, які виконуються при 
	** не дійсності умови 2 */
}

/* ... */

else if ( /* умова перевірки N */ )
{
	/* оператори, які виконуються при 
	** не дійсності умови N */
}
else
{
	/* оператори, які виконуються при 
	** хибності усіх попередніх умов */
}
Для множинних умов найкраще використовувати оператор switch. Його синтаксис наступний:
switch ( /* умовний вираз */ )
{
	case /* значення_1 */:
 		/* оператори при значення умовного виразу “значення_1” */
		break ;

	/* ... */

	case /* значення_N */:
 		/* оператори при значення умовного виразу “значення_N” */
		break ;

	default:
		/* оператори при не співпаданні з жодним 
		** значенням  умовного виразу */
}
В даному операторі слід не забувати ставити оператор break після команд кожного з можливих значень умови, в іншому випадку інструкції будуть виконуватись по-порядку, до поки не зустрінуть оператор break, або закінчення блоку оператора switch. В Java, як і у більшості сучасних мовах, також присутній тернарний оператор вибірки. Який відрізняється тим, що на відміну від звичайного оператора if, тернарний оператор здатний не тільки виконувати обчислення, а й повертати значення. Синтаксис тернарного оператора:
/* умова */ ? /* оператори_1 */ : /* оператори_2 */ ;
В разі справедливості умови обчислюється і повертається значення блоку “оператори_1”, якщо умова хибна, обчислюються і повертається значення блоку “оператори_2”.

Цикли

В Java є три типи циклів: цикл for, цикл з передумовою і цикл з після умовою. Синтаксис циклу for:
for ( /* початкові значення */ ; /* охоронна умова циклу */ ; /* оператор ітерації */ )
{
	/* оператори, які виконуються циклічно,
	** поки справедлива умова в охороні циклу */
}
Синтаксис циклу з передумовою:
while ( /* умова охорони циклу */ )
{
	/* оператори, які виконуються циклічно,
	** поки справедлива умова в охороні циклу */	
}
Синтаксис циклу з після умовою:
do
{
	/* оператори, які виконуються хоча б один раз */
}
while ( /* умова охорони циклу */ ) ;
На кожній ітерації, цикл можна перервати взагалі, або примусово завершити поточну ітерацію за допомогою операторів break і continue відповідно.

Класи

Java являється “ідеалізованою” мовою програмування, з точки зору компромісу між підтримуваними парадигмами або ж стилями. На відміну від мови С++, яка підтримує парадигму об'єктно-орієнтованого програмування і процедурного, Java підтримує тільки об'єктно-орієнтоване програмування. Саме тому, існування вільних методів або ж функцій, які не входять у склад будь-якого класу, неможливе, і тому переходимо одразу ж до класів. Синтаксис оголошення класу наступний:
class /* ім'я класу */
{
	/* нутрощі класу */
}
Всередині класу, як для будь-якої об'єктно-орієнтованої мови, можуть бути присутніми як дані або поля класу, так і методи або функції класу. Це виражає таку ідею ООП, як інкапсуляція. Метод класу можна оголосити наступним чином:
/* тип повернення */ /* ім'я методу */ ( /* параметри */ )
{
	/* тіло методу */
}
“Тип повернення” може бути як вбудованим стандартним типом, так і типом, створеним користувачем. “Ім'я методу” це ідентифікатор функції, через який до неї звертаються. “Параметри” методу це ті змінні, з якими буде мати справу даний метод. Вони також можуть бути стандартним вбудованим, або типом створеним користувачем. Що характерно, стандартні вбудовані типи передаються по значенні, тобто створюється копія об'єкту і операції в середині методу над переданим об'єктом не будуть зберігатися після завершення виконання методу. А об'єкти, тип яких оголосив користувач, тобто нові класи, передаються як посилання, і операції, які відбувалися над об'єктом в середині методу будуть збереженими після завершення виконання методу, так як оригінальний об'єкт і об'єкт переданий методу — один. В середині тіла методів класу можливе використання спеціальних об'єктів-посилань this і super. Об'єкт this це вказівник на поточний клас, а super — це вказівник на примірник батьківського класу до даного. Наприклад, створимо клас Coordinate, який буде зберігати двовимірну координату на осях абсцис і ординат:
class Coordinate 
{ 
    /* координати - 
    ** приватні члени */ 
    private double _x ; 
    private double _y ; 


    /* методи доступу до 
    ** приватних членів */    
    public double x () 
    { return _x ; } 
    
    public double y () 
    { return _y ; } 
    
    /* перевантажені методи 
    ** для встановлення значень */ 
    public void x (double sx) 
    { _x = sx ; } 
    
    public void y (double sy) 
    { _y = sy ; } 
    
    /* конструктори */ 
    Coordinate () 
    { 
        _x = 0.0 ; 
        _y = 0.0 ; 
    } 
    
    Coordinate (double sx, double sy) 
    { 
        _x = sx ; 
        _y = sy ; 
    } 
}
Якщо добре придивитись до даного прикладу, можна виявити методи класу, які мають те ж саме ім'я, що і сам оголошуваний клас. Такі методи називаються конструкторами і викликаються вони автоматично під час створення кожного примірника даного класу. Перед кожним методом чи полем класу, ми можемо вказати специфікатори доступу до даного члена класу. Члени класу можуть бути:
  • відкритими “public”, які доступні ззовні класу;
  • закритими, або приватними “private”, які використовуються тільки всередині класу і не доступні будь-де в програмі, окрім внутрішніх методів класу;
  • і захищеними “protected”, які відрізняються від приватних тим, що до них можна звернутися з потомків поточного класу.
Якщо не вказаний буд-який специфікатор доступу, вважається що даний член відкритий. Також метод або поле класу можуть бути статичними (“static”), що робить його спільним для усіх примірників класу (для усіх об'єктів класу). Статичні методи можна викликати з будь-якого об'єкта даного класу, або з самого класу через оператор доступу (“.”). Статичні члени ініціалізовуються в необов'язковому статичному блоці:
static 
{
	/* ініціалізація статичних змінних */
}
Наприклад
class StaticMembers 
{ 
    public static int a ; 
    
    static 
    { 
        a = 19 ; 
    } 
}
Будь-який клас в Java може мати батьківський клас і тільки один, але батьківський клас може мати багато потомків (класи дочірні даному). Щоб зробити клас дочірнім до будь-якого іншого, слід після ідентифікатора нового класу, вказати ключове слово-оператор extends, після якого вказати ім'я батьківського класу і відповідно тіло нового класу. Синтаксис:
class /* ім'я дочірнього*/ extends /* ім'я батьківського */
{
	/* дочірнього */
}
Наприклад, можна розширити функціонал програми, створивши потомок класу Coordinate, з попередніх прикладів, який буде в змозі зберігати три координати замість двох:
class Coordinate3D extends Coordinate 
{ 
    /* додаткова координата глибини */ 
    private double _z ; 

    /* методи доступу до 
    ** приватних членів */    
    public double z () 
    { return _z ; } 
    
    /* перевантажені методи 
    ** для встановлення значень */ 
    public void z (double sz) 
    { _z = sz ; } 
    
    Coordinate3D () 
    { _z = 0.0 ; } 
    
    Coordinate3D (double sx, double sy, double sz) 
    { 
        x (sx) ; 
        y (sy) ; 
        z (sz) ; 
    } 
    
    /* конструктори копіювання */ 
    Coordinate3D (Coordinate3D other) 
    { 
        x (other.x ()) ; 
        y (other.y ()) ; 
        z (other.z ()) ; 
    } 
} 
Клас Coordinate3D має власне поле “_z” і методи “z” для зберігання і використання координати глибини, а також методи “x” і “y”, які унаслідувані ним від батьківського класу Coordinate. Слід звернути увагу що з класу Coordinate3D немає доступу до батьківських приватних членів “_x” i “_y”. Для того, щоб Java-класи підтримував множинну спадковість використовують конструкції на подобі інтерфейсів. Один клас може реалізовувати декілька інтерфейсів. Також можливо присвоїти інтерфейсній змінній примірник класу, який його реалізовує (так само як у батьківських класах). Синтаксис оголошення інтерфейсу:
interface /* ім'я інтерфейсу */
{
	/* сигнатури методів і глобальних констант */
}
Інтерфейс повинен містити тільки сигнатури методів, а усі поля оголошені у ньому, автоматично стають константами (автоматично отримують специфікатори public і final). Щоб вказати, що клас реалізовує інтерфейс, необхідно скористатися ключовим словом implements і, через кому у разі їх множинності, вказати імена інтерфейсів. Наприклад:
interface NiceInter 
{ 
    void show () ; 
}

interface NiceInter2
{
	void print () ;
}

class NiceClass implements NiceInter, NiceInter2
{ 
    public void show () 
    { 
        System.out.println ("Hallo, this is NiceInter.show from NiceClass") ; 
    } 

    public void print ()
    {
        System.out.println ("Hallo, this is NiceInter2.print from NiceClass") ; 
    }
}

Приклади програм

Розглянемо декілька прикладів програм на Java. Просте сортування вибором:
/*
** Прикла Java програми.
** Сортування вибором.
*/

class MainClass
{
    public static void main (String[] opts)
    {
        // створюємо масив
        int[] iArray = new int[] {17, 11, 3, 19, 2, 5, 7, 1, 0, 13, 15} ;
        int x, pos ;

        // виводимо масив на екран        
        for (int iter=0; iter<iArray.length; ++iter)
        { System.out.print (iArray[iter] + " ") ; }
        
        System.out.println() ;
        
        // цикл сортування 
        for (int iter=0; iter<iArray.length; ++iter)
        {
            pos = iter ;
            x = iArray [pos] ;
            
            for (int jter=iter+1; jter<iArray.length; ++jter)
            {
                if (x>iArray[jter])
                {
                    pos = jter ;
                    x = iArray [jter] ;
                }
            }
            
            iArray [pos]  = iArray [iter] ;
            iArray [iter] = x ;
        }

        // виводимо масив на екран
        for (int iter=0; iter<iArray.length; ++iter)
        { System.out.print (iArray[iter] + " ") ; }
        
        System.out.println() ;
    }
}
Бульбашкове сортування:
/*
** Прикла Java програми.
** Бульбашкове сортування.
*/

class MainClass
{
    public static void main (String[] opts)
    {
        // створюємо масив
        int[] iArray = new int[] {17, 11, 3, 19, 2, 5, 7, 1, 0, 13, 15} ;
        int x ;

        // виводимо масив на екран
        for (int iter=0; iter<iArray.length; ++iter)
        { System.out.print (iArray[iter] + " ") ; }
        
        System.out.println() ;

        // цикл сортування                
        for (int iter=0; iter<iArray.length-1; ++iter)
        {
            for (int jter=iter+1; jter<iArray.length; ++jter)
            {
                if (iArray[iter]>iArray[jter])
                {
                    x = iArray [iter] ;
                    iArray [iter] = iArray [jter] ;
                    iArray [jter] = x ;
                }
            }
        }
        
        // виводимо сортований масив на екран
        for (int iter=0; iter<iArray.length; ++iter)
        { System.out.print (iArray[iter] + " ") ; }
        
        System.out.println() ;
    }
}

Резюме

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