Система неявно заохочувала створення кожним програмістом своєї власної підмножини мови, невідомої решті світу. У міру розростання кодів збільшується той смисловий контекст, в якому компілятор інтерпретує кожен рядок програми. Вже в проектах середнього розміру істотно зростає навантаження на компілятор, не говорячи вже про навантаження на пам'ять програміста.
Єдина важлива функція препроцесора, що залишилася — дозволити включення в програму файлів-заголовків з описами класів. Ця операція може бути виконана просто і ефективно, якщо дозволити компілятору читати підготовлені бінарні файли з описом класів. Останній напрямок був вибраний при створенні мови Java.
Всі ці міркування дозволили повністю виключити необхідність використання текстового препроцесора в мові Java.
Структури struct і union не мають сенсу в Java, їх роль повністю виконують класи. Використання конструкцій типу union для типізованих об'єктів також більше не потрібне — мова дозволяє визначити тип об'єкту при виконанні програми.
В цьому сенсі Java чисто об'єктно-орієнтована система. Функції і процедури, не прив'язані до контексту якого-небудь об'єкту, більше не присутні в системі. За ситуації, коли функція логічно не прив'язана до певного екземпляра класу, вона може бути створена як метод самого класу (тобто мати тип static).
Послідовна реалізація концепції множинного наслідування в С++ привела до істотних труднощів як в створенні компіляторів, так і у використанні його (множинного наслідування) в програмах. Як альтернатива Java використовує поняття інтерфейсу, що визначає набір методів, які повинні бути визначені в класі, що реалізовує цей інтерфейс.
Інтерфейс може також містити визначення деяких констант.
Те, чого інтерфейс містити не може, — це реалізації методів або змінні поля даних. Класи, які оголошені, що реалізують той або інший інтерфейс, зобов'язані реалізувати всі методи, оголошені в інтерфейсі.
Досвід використання перевантажених операторів в С++ показує, що вони мають сенс в досить обмеженому наборі ситуацій. З іншого боку, зловживання цією властивістю може зробити програму абсолютно незрозумілою. Єдине “вбудоване” в мову Java виключення — можливість використання оператора “+” для склеювання рядків.
В мові Java заборонено автоматичне перетворення типів, широко використовуване (і рекомендоване) в С++. Щоб перетворити елемент одного типу в іншій, необхідно вказати це явно, наприклад: int myInt; double myFloat = 3.14159; myInt = myFloat; // допустимо в С++, неприпустимо в Java myInt = (int)myFloat; // допустимо в Java. Виняток становить перетворення між вбудованими чисельними типами без втрати інформації.
Більшість досліджень показали, що застосування покажчиків в С/С++ є одним з основних джерел помилок. Внаслідок того, що в мові більше не стало структур, а масиви і рядки перетворилися на повноцінні об'єкти, потреба в покажчиках відпала.
Вміст рядків і масивів доступно тільки по індексах, причому контроль доступу під час виконання не дозволяє виходити за межі масиву або рядка.
Отже, ми показали дві з основних властивостей мови програмування Java:
- знайомий — Java зберігає стиль програмування C і С++;
- простий — кількість конструкцій мови в Java істотно скорочена в порівнянні із С і С++;
Система Java створювалася об'єктною орієнтованою із самого початку. Об'єктно-орієнтована парадигма найбільш зручна при створенні програмного забезпечення типу клієнт-сервер, а також для організації розподілених обчислень.
Одна з рис, властивих об'єктам, полягає в тому, що об'єкти зазвичай переживають процедуру, що їх створює. Вони потім можуть переміщатися по мережі, зберігатися в базах даних і т.д.
Ідейними спадкоємцями Java є такі мови, як C++, Eiffel, Smalltalk і Objective C. За винятком примітивних типів даних, практично все в мові є об'єктом.
Основні вимоги до об'єктно-орієнтованої системи:
- інкапсуляція — захована реалізація за абстрактним інтерфейсом;
- поліморфізм — одне і те ж повідомлення, послане різним об'єктам, приводить до виконання різних операцій;
- спадкоємство — нові класи можуть успадковувати дані і функціональність вже існуючих класів;
- динамічне скріплення — нові класи можуть з'являтися в системі звідки завгодно, у тому числі і з мережі. Необхідно мати можливість динамічно включати їх в систему.
Клас є мовна конструкція, що визначає поля даних об'єктів даного класу (instance variables) і їх поведінку (methods). Практично клас в Java сам по собі не є об'єктом. Це лише шаблон, який визначає, з яких частин складатиметься об'єкт, створений за допомогою цього класу, і як він поводитиметься.
Простий приклад опису класу:
class Point extends Object { public double x; public double у; }
Створити об'єкт описаного вище класу можна декларацією: Point myPoint; // оголошення змінної типа Point myPoint = new Point(); myPoint.x = 10.0; myPoint.y = 25.7;.
При оголошенні класу можливо вказати методи спеціального вигляду, названі конструкторами і призначені для ініціалізації створеного об'єкту. Ім'я цих методів повинне співпадати з ім'ям класу, вони можуть мати певну кількість аргументів, наприклад: class Point extends Object { Point() { x = 0.0; у = 0.0; } Point(double x, double у) { this.x = x; this.y = у; } public double x; public double у; }, а використані вони можуть бути таким чином: Point а; Point b; а = new Point(); b = new Point(1.0, 2.0); - ім'я this у визначенні конструктора з аргументами використовується для позначення самого об'єкту, в методі якого ми знаходимося, в тих випадках, коли посилання на цей об'єкт не є явним.
Якщо один об'єкт в програмі примушує інший виконувати якусь операцію, то прийнято говорити, що він посилає повідомлення іншому об'єкту. Наприклад, ми можемо перевизначити наш клас таким чином: Pclass Point extends Object { private double x; private double у; public void setX(double x) { this.x = x; } public void setН(double у) { this.y = у; }… }. Ми тепер зробили поля x і у недоступними ззовні класу, але для зміни їх стану передбачили спеціальні методи setX і setY.
Спеціальне ім'я finalize зарезервоване для методу, який буде викликаний збирачем сміття перед тим, як об'єкт буде знищений. Внаслідок того, що Java звільняє нас від необхідності самим стежити за звільненням пам'яті, займаної об'єктами, необхідність в таких методах зазвичай виникає лише тоді, коли треба звільнити якісь зовнішні ресурси, наприклад, закрити відкритий файл: protected void finalize() { try { file.close(); } catch (Exception e) { } }.
Спадкоємство класів дозволяє створювати нові типи об'єктів, що ефективно використовують функціональність вже існуючих типів. Новий тип зазвичай називається похідним класом, а той, чиї властивості успадковуються, — базовим класом.
Наприклад, ми можемо описати новий клас, відповідний координатам точки в тривимірному просторі, на основі вже описаного класу для точки на площині: class ThreePoint extends Point { protected double z; ThreePoint() { super(); z = 0.0; } ThreePoint(double x, double у, double z) { super(x, у); this.z = z; }}. Тут ми додали нову координату z, а поля x і у (і методи доступу до них) успадкували від класу Point.
Контроль доступу до даних і методів об'єкту в Java дещо відрізняється від С++. Крім трьох рівнів доступу, наявних в С++ (public, private, protected) є четвертий, такий, що знаходиться десь між рівнями public і protected. Він не має імені і використовується за умовчанням, коли явно не вказаний інший рівень. Поля цього типу доступні всередині тільки одного програмного пакету.
Пакет представляє групу класів, об'єднаних в одну логічну групу. Наприклад, класи, що описують точку і прямокутник в графічному пакеті, можуть мати прямий доступ до полів даних один одного, заборонений зазвичай для решти середовища.
Також слід зазначити, що контроль доступу в C++ допомагає програмістові лише при побудові програми. Відмінності між полями, поміченими public і private, відсутні у виконуваному модулі, створеному з використанням цієї мови. У Java контроль доступу реальний, оскільки він здійснюється не тільки при компіляції, але і безпосередньо перед запуском кодів на виконання віртуальною машиною.
Як і С++ мова Java дозволяє використовувати змінні і методи, що належать класу цілком. Для визначення їх використовується ключове слово static. Природно, що методи самого класу не можуть оперувати даними і методами об'єкту класу, оскільки вони не відносяться ні до якогось певного об'єкту.
Наприклад, версія реалізації класу Rectangle може бути задана таким чином: class Rectangle extends Object { static final int version = 2 ; static final int revision = 0 ; } Ключове слово final означає, що значення поля остаточне і зміні не підлягає (це константа).
Абстрактні методи — це методи, для яких в даному класі не визначена їх реалізація. Ми указуємо лише на необхідність наявності методів з даним протоколом. Конкретна реалізація повинна бути здійснена класами-спадкоємцями. В той же час інша, “неабстрактна” частина класу може містити конкретну інформацію, яка може бути використана похідними класами. Наприклад: abstract class Graphical extends Object { protected Point lowerLeft; protected Point upperRight; … public void setPosition(Point ll, Point ur) { lowerLeft = ll; upperRight = ur; } abstract void drawMyself(); } class Rectangle extends Graphical { void drawMyself() { …. } } Тут ми описали клас Graphical.
У ньому оголошена властивість всіх графічних елементів мати якесь положення на площині. Кожен елемент зобов'язаний також мати метод для малювання самого себе, проте ніякого методу малювання за замовчуванням бути не може. Клас Rectangle, що є конкретною реалізацією для типа Graphical, реалізує також цей метод для об'єкту прямокутної форми.
Клас, що містить хоч би один абстрактний метод, повинен бути оголошений як абстрактний. Із зрозумілих причин створення екземплярів такого класу неможливе.
Таким чином ми висвітили наступні сторони Java як об'єктно-орієнтованої мови програмування:
- класи визначають шаблон, по якому створюються конкретні об'єкти;
- поля даних об'єкту визначають стан об'єкту;
- об'єкти обмінюються повідомленнями між собою; отримання повідомлення приводить до виклику одного з методів;
- методи визначають поведінку об'єкту даного класу; методи для різних класів можуть мати одне і те-ж ім'я, але різний зміст;
- не залежна від архітектури, переносима і інтелектуальна;