Читайте также: |
|
Другим фундаментальним властивістю об'єктно-орієнтованого підходу є спадкування (перший - інкапсуляція). Класи-нащадки мають можливість не тільки створювати свої власні змінні і методи, але й наслідувати змінні і методи класів-предків. Класи-нащадки прийнято називати підкласами. Безпосереднього предка даного класу називають його суперкласом. У черговому прикладі показано, як розширити клас Point таким чином, щоб включити в нього третю координату z.
class Point3D extends Point {int z;
Point3D (int x, int y, int z) {
this.x = x;
this.у = у;
this.z = z;}
Point3D () {
this (-1, -1, -1);
}}
У цьому прикладі ключове слово extends використовується для того, щоб повідомити транслятору про намір створити підклас класу Point. Як бачите, в цьому класі не знадобилося оголошувати змінні х і у, оскільки Point3D успадкував їх від свого суперкласу Point.
УВАГА
Ймовірно, програмісти, знайомі з C + +, очевидно очікують, що зараз ми почнемо обговорювати концепцію множинного спадкоємства. Під множинним спадкуванням розуміється створення класу, який має кілька суперкласів. Однак в мові Java заради забезпечення високої продуктивності та більшої ясності вихідного коду множинне спадкоємство реалізоване не було. У більшості випадків, коли потрібна множинне спадкування, проблему можна вирішити за допомогою наявного в Java механізму інтерфейсів, описаного в наступному розділі.
super
У прикладі з класом Point3D частково повторювався код, вже яким в суперкласу. Згадайте, як у другому конструкторі ми використовували this для виклику Перший конструктор того ж класу. Аналогічним чином ключове слово super дозволяє звернутися безпосередньо до конструктора суперкласу (в Delphi / С + + для цього використовується ключове слово inherited).
class Point3D extends Point {int z;
Point3D (int x, int у, int z) {
super (x, y); / / Тут ми викликаємо конструктор суперкласу this.z = z;
public static void main (String args []) {
Point3D p = new Point3D (10, 20, 30);
System.out.println ("x =" + px + "y =" + py +
"Z =" + p.z);
}}
Ось результат роботи цієї програми:
С: \> java Point3D
x = 10 у = 20 z = 30
Заміщення методів
Новий підклас Point3D класу Point успадковує реалізацію методу distance свого суперкласу (приклад PointDist.java). Проблема полягає в тому, що в класі Point вже визначена версія методу distance (mt х, int у), яка повертає звичайне відстань між точками на площині. Ми повинні замістити (override) це визначення методу новим, придатним для випадку тривимірного простору. У наступному прикладі проілюстровано і суміщення (overloading), і заміщення (overriding) методу distance.
class Point {int х, у;
Point (int х, int у) {
this.x = х;
this.у = у;
}
double distance (int х, int у) {
int dx = this.x - х;
int dy = this.у - у:
return Math, sqrt (dx * dx + dy * dy);
}
double distance (Point p) {
return distance (p.х, p.y);
}
}
class Point3D extends Point {int z;
Point3D (int х, int y, int z) {
super (x, y);
this.z = z;
(
double distance (int х, int y, int z) {
int dx = this.x - х;
int dy = this.y - y;
int dz = this.z - z;
return Math.sqrt (dx * dx + dy * dy + dz * dz);
}
double distance (Point3D other) {
return distance (other.х, other.y, other.z);
}
double distance (int х, int y) {
double dx = (this.x / z) - х;
double dy = (this.у / z) - y;
return Math.sqrt (dx * dx + dy * dy);
}
}
class Point3DDist {
public static void main (String args []) {
Point3D p1 = new Point3D (30, 40, 10);
Point3D p2 = new Point3D (0, 0, 0);
Point p = new Point (4, 6);
System.out.println ("p1 =" + p1.x + "," + p1.y + "," + p1.z);
System.out.println ("p2 =" + p2.x + "," + p2.y + "," + p2.z);
System.out.println ("p =" + p.x + "," + p.y);
System.out.println ("p1.distance (p2) =" + p1.distance (p2));
System.out.println ("p1.distance (4, 6) =" + p1.distance (4, 6));
System.out.println ("p1.distance (p) =" + p1.distance (p));
}}
Нижче наводиться результат роботи цієї програми:
С: \> Java Point3DDist
p1 = 30, 40, 10
р2 = 0, 0, 0
р = 4, 6
p1.distance (p2) = 50.9902
p1.distance (4, 6) = 2.23607
p1.distance (p) = 2.23607
Зверніть увагу - ми отримали очікуване відстань між тривимірними точками і між парою двовимірних точок. У прикладі використовується механізм, який називається динамічним призначенням методів (dynamic method dispatch).
8.Динамічне призначення методів
Давайте як приклад розглянемо два класи, у яких мають просте спорідненість підклас / суперклас, причому єдиний метод суперкласу заміщений в підкласі.
class A {void callme () {
System.out.println ("Inside A's callrne method");
class В extends A {void callme () {
System.out.println ("Inside B's callme method");
}}
class Dispatch {
public static void main (String args []) {
A a = new B ();
a.callme ();
}}
Зверніть увагу - всередині методу main ми оголосили змінну а класу А, а проініціалізувати її посиланням на об'єкт класу В. У наступному рядку ми викликали метод callme. При цьому транслятор перевірив наявність методу callme у класу А, а виконуюча система, побачивши, що насправді в змінній зберігається представник класу В, викликала не метод класу А, а callme класу В. Нижче наведено результат роботи цієї програми:
С: \> Java Dispatch
Inside B's calime method
РАДА
Програмістам Delphi / C + + слід зазначити, що всі Java за замовчуванням є віртуальними функціями (ключове слово virtual).
Розглянута форма динамічного поліморфізму часу виконання являє собою один з найбільш потужних механізмів об'єктно-орієнтованого програмування, що дозволяють писати надійний, багаторазово використовуваний код.
Final
Всі методи і змінні об'єктів можуть бути заміщені за замовчуванням. Якщо ж ви хочете оголосити, що підкласи не мають права заміщати будь змінні і методи вашого класу, вам потрібно оголосити їх як final (в Delphi / C + + не писати слово virtual).
final int FILE_NEW = 1;
По загальноприйнятій угодою при виборі імен змінних типу final - використовуються тільки символи верхнього регістру (тобто використовуються як аналог препроцерних констант C + +). Використання final-методів деколи приводить до виграшу в швидкості виконання коду - оскільки вони не можуть бути заміщені, транслятору ніщо не заважає замінювати їх виклики вбудованим (in-line) кодом (байт-код копіюється безпосередньо в код зухвалого методу).
Finalize
У Java існує можливість оголошувати методи з ім'ям finalize. Методи finalize аналогічні деструкторів в C + + (ключовий знак ~) і Delphi (ключове слово destructor). Виконуюча середу Java буде викликати його кожного разу, коли збирач сміття збереться знищити об'єкт цього класу.
Static
Іноді потрібно створити метод, який можна було б використовувати поза контекстом якого об'єкта його класу. Так само, як у випадку main, все, що потрібно для створення такого методу - вказати при його оголошенні модифікатор типу static. Статичні методи можуть безпосередньо звертатися тільки до інших статичним методам, в них ні в якому вигляді не допускається використання посилань this й super. Змінні також можуть мати тип static, вони подібні глобальним змінним, тобто доступні з будь-якого місця коду. Усередині статичних методів неприпустимі посилання на змінні представників. Нижче наведено приклад класу, у якого є статичні змінні, статичний метод і статичний блок ініціалізації.
class Static {
static int a = 3;
static int b;
static void method (int x) {
System.out.println ("x =" + x);
System.out.println ("a =" + a);
System.out.println ("b =" + b);
}
static {
System.out.println ("static block initialized");
b = a * 4;
}
public static void main (String args []) {
method (42);
}}
Нижче наведено результат запуску цієї програми.
С: \> java Static static block initialized
Х = 42
А = 3
B = 12
У наступному прикладі ми створили клас зі статичним методом і декількома статичними змінними. Другий клас може викликати статичний метод по імені і посилатися на статичні змінні безпосередньо через ім'я класу.
class StaticClass {
static int a = 42;
static int b = 99;
static void callme () {
System.out.println ("a =" + a);
}}
class StaticByName {
public static void main (String args []) {
StaticClass.callme ();
System.out.println ("b =" + StaticClass.b);
}}
А ось і результат запуску цієї програми:
С: \> Java StaticByName
а = 42 b = 99
Abstract
Бувають ситуації, коли потрібно визначити клас, в якому задана структура небудь абстракції, але повна реалізація всіх методів відсутня. У таких випадках ви можете за допомогою модифікатора типу abstract оголосити, що деякі з методів обов'язково повинні бути заміщені у підкласах. Будь клас, що містить методи abstract, також має бути оголошений, як abstract. Оскільки у таких класів відсутня повна реалізація, їх представників не можна створювати за допомогою оператора new. Крім того, не можна оголошувати абстрактними конструктори і статичні методи. Будь підклас абстрактного класу або зобов'язаний надати реалізацію всіх абстрактних методів свого суперкласу, або сам має бути оголошений абстрактним.
abstract class A {
abstract void callme ();
void metoo () {
System.out.println ("Inside A's metoo method");
}}
class B extends A {
void callme () {
System.out.println ("Inside B's callme method");
}}
class Abstract {
public static void main (String args []) {
A a = new B ():
a.callme ():
a.metoo ():
}}
У нашому прикладі для виклику реалізованого в підкласі класу А методу callme і реалізованого в класі А методу metoo використовується динамічне призначення методів, яке ми обговорювали раніше.
С: \> Java Abstract
Inside B's callrne method Inside A's metoo method
Дата добавления: 2015-10-29; просмотров: 132 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Конструктори | | | Подключение библиотеки JDOM |