Привет! В предыдущих лекциях мы уже несколько раз мельком встречались с таким понятием как наследование.
Сегодня мы тоже коснемся этой темы, но тоже не слишком глубоко. Подробная лекция об этом еще будет, а сегодня скорее просто посмотрим практические примеры и познакомимся с одним интересным оператором в 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, и сравнивать его со строкой, что, конечно, было бы неправильно.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ