Вітання! У попередніх лекціях ми вже кілька разів мигцем зустрічалися з таким поняттям, як спадкування. Сьогодні ми теж торкнемося цієї теми, але теж не надто глибоко. Детальна лекція про це ще буде, а сьогодні швидше просто подивимося практичні приклади та познайомимося з одним цікавим оператором Java.
Спадкування - це механізм у програмуванні, у тому числі і в Java, який дозволяє описати новий клас на основі вже існуючого. Клас-спадкоємець при цьому отримує доступ до полів та методів батьківського класу. Навіщо це може бути потрібне? Ну, наприклад, уяви, що тобі потрібно створити в програмі кілька класів машин: Вантажівка, Гоночна, Седан, Пікап і т.д. Навіть не приступивши до написання коду, ти точно знаєш, що ці класи мають дуже багато спільного: у всіх машин є назва моделі, рік випуску, об'єм двигуна, максимальна швидкість і т.д. (Не кажучи вже про те, що у них є колеса та інші деталі). У такій ситуації ти можеш:
Успадкування Java
Отже, що таке, власне, успадкування?
Спадкування - це механізм у програмуванні, у тому числі і в Java, який дозволяє описати новий клас на основі вже існуючого. Клас-спадкоємець при цьому отримує доступ до полів та методів батьківського класу. Навіщо це може бути потрібне? Ну, наприклад, уяви, що тобі потрібно створити в програмі кілька класів машин: Вантажівка, Гоночна, Седан, Пікап і т.д. Навіть не приступивши до написання коду, ти точно знаєш, що ці класи мають дуже багато спільного: у всіх машин є назва моделі, рік випуску, об'єм двигуна, максимальна швидкість і т.д. (Не кажучи вже про те, що у них є колеса та інші деталі). У такій ситуації ти можеш:
- Створювати ці поля у кожному класі та додавати їх у нові класи машин при їх створенні
- Винести загальні для всіх машин поля в батьківський клас
Car, а всі класи конкретних типів машин успадковуватиCarза допомогою слова extends .
public class Car {
private String model;
private int maxSpeed;
private int yearOfManufacture;
public Car(String model, int maxSpeed, int yearOfManufacture) {
this.model = model;
this.maxSpeed = maxSpeed;
this.yearOfManufacture = yearOfManufacture;
}
}
public class Truck extends Car {
public Truck(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
public class Sedan extends Car {
public Sedan(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
} Як мінімум, ми уникнули непотрібного дублювання коду, а цього завжди потрібно прагнути при написанні програм. Крім того, ми маємо просту і зрозумілу структуру класів: загальні для всіх машин поля винесені в один клас. Якщо, наприклад, вантажівки мають якісь специфічні поля, яких немає в інших машин, їх можна оголосити в класі Truck. Те саме стосується і методів. У всіх автомобілів є якась загальна поведінка, яку можна описати: завести авто, газ/гальмо тощо. Ці загальні методи можна винести на загальний клас Car, а специфічне поведінки кожного конкретного типу описати у класах-спадкоємцях.
public class Car {
public void gas() {
//...газ
}
public void brake() {
//...гальмо
}
}
public class F1Car extends Car {
public void pitStop() {
//...піт-стоп роблять тільки гоночні автомобілі
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
} Ми винесли загальні методи всіх автомобілів у клас Car. А ось у клас-спадкоємець F1Car, який описує гоночні автомобілі "Формули-1" - піт-стопи (зупинки для термінового обслуговування машини), які роблять тільки в гонках та вирізняються специфічною поведінкою.
Оператор instanceof Java
Для перевірки того, чи створено об'єкт на основі якогось класу, Java існує спеціальний оператор —instanceof. Він повертає значення true, якщо перевірка показала істинність, або falseякщо результат був помилковим. Давай подивимося, як він працює на прикладі наших класів із машинами:
public class Truck extends Car {
public static void main(String[] args) {
Truck truck = new Truck();
System.out.println(truck instanceof Car);
}
}Висновок: true Перевірка за допомогою оператора instanceofповернула true, оскільки у нас об'єкт класу Truck, а всі вантажівки – це машини. Клас Truck- спадкоємець класу Car, отже, всі вантажівки створюються на основі спільного батька - машини. Зверніть увагу на оператор instanceof: він пишеться без точки, оскільки це саме оператор, а не метод (“об'єкт instanceof Клас”). Спробуємо по-іншому:
public static void main(String[] args) {
Car car = new Car();
System.out.println(car instanceof Truck);
}Висновок: false Клас Carі, відповідно, його об'єкт не походять від класу Truck. Усі вантажівки – це машини, але не всі машини – вантажівки. Об'єкти Carне створюються на основі класу Truck. Ще один приклад:
public static void main(String[] args) {
Car car = new Car();
Truck truck = new Truck();
System.out.println(car instanceof Object && truck instanceof Object);
}Висновок: True Тут логіка теж проста: всі класи в Java, включаючи ті, які ти створив, походить від класу Object(хоча ти і не пишеш у них extends Object - цей механізм закладений у них неявно). Навіщо це може стати в нагоді і за яких обставин? Найбільш поширене застосування оператора instanceof- це перевизначення методу equals(). Наприклад, ось як реалізований спосіб equalsу класі String:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
} Перш ніж порівняти рядок з переданим об'єктом, метод перевіряє: а чи є власне переданий об'єкт рядком? І тільки потім він починає порівнювати властивості двох об'єктів. Без цієї перевірки метод можна було б передати будь-який об'єкт, у якого є поля value і length , і порівнювати його з рядком, що, звичайно, було б неправильно.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ