Наследование. Преимущество наследования

Открыта

— Привет, Амиго! Сейчас будет одна тема, которой, я думаю, ты будешь частенько пользоваться. Это – наследование.

Программирование, для несведущих, неотличимо от магии. Поэтому начну с такой интересной аналогии…

Предположим, что ты волшебник и хочешь создать летающую лошадь. С одной стороны, ты бы мог попробовать наколдовать пегаса. Но т.к. пегасов в природе не существует, это будет очень непросто. Придется очень много делать самому. Куда проще взять лошадь и приколдовать ей крылья.

Наследование. Преимущество наследования - 1

В программировании такой процесс называется «наследование». Предположим тебе нужно написать очень сложный класс. Писать с нуля долго, потом еще долго все тестировать и искать ошибки. Зачем идти самым сложным путем? Лучше поискать – а нет ли уже такого класса?

Предположим, ты нашел класс, который своими методами реализует 80% нужной тебе функциональности. Ты можешь просто скопировать его код в свой класс. Но у такого решения есть несколько минусов:

1) Найденный класс уже может быть скомпилирован в байт-код, а доступа к его исходному коду у тебя нет.

2) Исходный код класса есть, но ты работаешь в компании, которую могут засудить на пару миллиардов за использование даже 6 строчек чужого кода. А потом она засудит тебя.

3) Ненужное дублирование большого объема кода. Кроме того, если автор чужого класса найдет в нем ошибку и исправит ее, у тебя эта ошибка останется.

Есть решение потоньше, и без необходимости получать легальный доступ к коду оригинального класса. В Java ты можешь просто объявить тот класс родителем твоего класса. Это будет эквивалентно тому, что ты добавил код того класса в код своего. В твоем классе появятся все данные и все методы класса-родителя. Например, можно делать так: наследуемся от «лошади», добавляем «крылья» — получаем «пегаса»

Наследование. Преимущество наследования - 2

— Очень интересно, продолжай.

— Наследование можно использовать и для других целей. Допустим, у тебя есть десять классов, которые очень похожи, имеют совпадающие данные и методы. Ты можешь создать специальный базовый класс, вынести эти данные (и работающие с ними методы) в этот базовый класс и объявить те десять классов его наследниками. Т.е. указать в каждом классе, что у него есть класс-родитель – данный базовый класс.

Также как преимущества абстракции раскрываются только рядом с инкапсуляцией, так и преимущества наследования гораздо сильнее при использовании полиморфизма. Но о нем я расскажу завтра. Сегодня же мы рассмотрим несколько примеров использования наследования.

Предположим, мы пишем программу, которая играет в шахматы с пользователем, тогда нам понадобятся классы для фигур. Какие бы ты предложил классы, Амиго?

— Король, Ферзь, Слон, Конь, Ладья и Пешка.

— Отлично. Ничего не упустил.

— А какие бы данные ты предложил хранить в этих классах?

— Координаты x и y, а также ее ценность (worth). Ведь некоторые фигуры ценнее других.

— А в чем отличия этих классов?

— Отличия в том, как они ходят, фигуры. В поведении.

— Да. Вот как можно было бы описать их в виде классов

class King
{
int x;
int y;
int worth;
void kingMove()
{
//код, решающий,
//как пойдет король
}
}
class Queen
{
int x;
int y;
int worth;
void queenMove()
{
//код, решающий,
//как пойдет ферзь
}
}
class Rook
{
int x;
int y;
int worth;
void rookMove()
{
//код, решающий,
//как пойдет ладья
}
}
class Knight
{
int x;
int y;
int worth;
void knightMove()
{
//код, решающий,
//как пойдет конь
}
}
class Bishop
{
int x;
int y;
int worth;
void bishopMove()
{
//код, решающий,
//как пойдет слон
}
}
class Pawn
{
int x;
int y;
int worth;
void pawnMove()
{
//код, решающий,
//как пойдет пешка
}
}
12
Задача
Java Core,  1 уровень,  5 лекция
Недоступна
Набираем код
Иногда думать не надо, строчить надо! Как ни парадоксально звучит, порой пальцы «запоминают» лучше, чем сознание. Вот почему во время обучения в секретном центре JavaRush вы иногда встречаете задания на набор кода. Набирая код, вы привыкаете к синтаксису и зарабатываете немного материи. А ещё — боретесь с ленью.

— Да, именно так я бы и написал.

— А вот, как можно было бы сократить код с помощью наследования. Мы могли бы вынести одинаковые методы и данные в общий класс. Назовем его ChessItem. Объекты класса ChessItem не имеет смысла создавать, так как ему не соответствует ни одна шахматная фигура, но от него было бы много пользы:

class King extends ChessItem
{
void kingMove()
{
//код, решающий,
//как пойдет король
}
}
class Queen extends ChessItem
{
void queenMove()
{
//код, решающий,
//как пойдет ферзь
}
}
class Rook extends ChessItem
{
void rookMove()
{
//код, решающий,
//как пойдет ладья
}
}
class ChessItem
{
int x;
int y;
int worth;
}
class Knight extends ChessItem
{
void knightMove()
{
//код, решающий,
//как пойдет конь
}
}
class Bishop extends ChessItem
{
void bishopMove()
{
//код, решающий,
//как пойдет слон
}
}
class Pawn extends ChessItem
{
void pawnMove()
{
//код, решающий,
//как пойдет пешка
}
}
12
Задача
Java Core,  1 уровень,  5 лекция
Недоступна
Набираем больше кода
Внимание! Объявляется набор кода на JavaRush. Для этого включите режим повышенной внимательности, расслабьте пальцы, читайте код и… набирайте его в соответствующем окошке. Набор кода — вовсе не бесполезное занятие, как может показаться на первый взгляд: благодаря ему новичок привыкает к синтаксису и запоминает его (современные IDE редко дают ему это сделать).

— Как интересно.

— Именно! Особенно много преимуществ мы получаем, когда в проекте тысячи различных объектов и сотни классов. Тогда правильно подобранными классами можно не только существенно упростить логику, но и сократить код в десятки раз.

— А что нужно чтобы унаследовать какой-то класс?

— Для этого после объявления нашего класса нужно указать ключевое слово extends и написать имя родительского класса. Унаследоваться можно только от одного класса.

Наследование. Преимущество наследования - 3

На картинке мы видим «корову», унаследованную от «свиньи». «Свинья» унаследована от «курицы», «курица» от «яйца». Только один родитель! Такое наследование не всегда логично. Но если есть только свинья, а очень нужна корова, программист зачастую не может устоять перед желанием сделать «корову» из «свиньи».

— А если мне хочется унаследоваться от двух классов. Можно же что-то сделать?!

— Почти ничего. Множественного наследования классов в Java нет: класс может иметь только одного класса-родителя. Но есть множественное наследование интерфейсов. Это немного снижает остроту проблемы.

— Ясно. А что такое интерфейс?

— Про интерфейсы я расскажу тебе завтра, а пока давай продолжим разбираться с наследованием.

Комментарии (80)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий вы должны авторизоваться
Ilya12 уровень, Москва
воскресенье, 18:56
Кто уже хорошо знаком с ООП... может мне объяснить почему бы не вынести метод move() в абстрактного родителя ChessItem?
Ilya12 уровень, Москва
воскресенье, 19:00
И если уже так хочется реализовывать методы движения фигур с уникальными названиями, просто вызывать kindhtMove(), bishopMove(), pawnMove() из соответсвующей реализации move(): class Knight extends Chess Item { public void move() { // <- реализуем бастрактный метод this.bishopMove(); }} ??
Stars_from7 уровень, Москва
воскресенье, 16:46
😂😂
Ivan Karataev12 уровень, Новосибирск
8 ноября, 06:52
Сколько теории, коллеги! Это радует)
SUPER FAM19 уровень, Sumy
5 ноября, 21:11
Понятно что в джаве нет множественного наследования, но так же каждый класс наследует класс Object + может наследовать любой другой один класс, а это уже получается множественное наследование. Хм
Гудини17 уровень, Санкт-Петербург
7 ноября, 18:01
Кстати, да, я об этом не подумал. ) С другой стороны, это наследование от Object неявное, генерируется при компиляции.
Valery Matyskin13 уровень, Минск
8 ноября, 20:31
Не так, совершенно. Если мы создали класс то он наследуется от Object, по умолчанию. Но при наследовании от другого класса, мы явно указываем от кого наследовать, а уже класс-родитель наследует Object, либо через своего класса-родителя, и так до Object. При таком взгляде на наследование двойственностью и не пахнет, но это не точно :-)
Гудини17 уровень, Санкт-Петербург
8 ноября, 22:03
Точно, если где-то в в предках переопределен toString(), наш класс будет использовать именно его. Спасибо.
Graf Vorontsov14 уровень, Черкассы
18 октября, 13:45
Все понятно
Алексей15 уровень, Полысаево
15 октября, 04:46
— Именно! Особенно много преимуществ мы получаем, когда в проекте тысячи различных объектов и сотни классов. Тогда правильно подобранными классами можно не только существенно упростить логику, но и сократить код в десятки раз. А если неправильно?
WantToSleep24 уровень, Москва
13 октября, 21:05
никого не смущает последняя картинка ?
Алексей15 уровень, Полысаево
15 октября, 04:44
Ну это суть беспощадности и бессмысленности злоупотребления ООП. Если его не контролировать, то вроде бы полезная технология разрастается в адскую химеру, которую потом замучаешься править при необходимости. В реальной жизни ООП это генетика - дети наследуют от родителей некоторые черты, не являясь при этом копиями родителей и действую самостоятельно, а иногда и от боле поздних предков(дедушки и бабушки). Но если в наследование пихать всё - получается такая вот картинка, как в лекции. Круто, но беспощадно. Где-то видел картинку, как раз про это. Мол, перед вами качок Василий, он крут и брутален, жмет 200 кг и усиленно питается, но разум у него как у школьника Пети, который только и мечтает, как бы списать контрольную и ничего не делать, а в подсознании у него сидит... Оппаа... А ты кто? А я Ирочка... Я хочу конфетку и бантики. Вывод: злоупотребление чем угодно до добра не доводит. Неважно чем, все-равно не доводит.
Валихан18 уровень, Санкт-Петербург
7 октября, 15:14
Как же мне нравится наследование! Супер принцип ООП! Еще и самый легкий на мой взгляд )
Vladyslav25 уровень
14 октября, 05:57
Когда начитается работа над новым большим проектом часто составляют UML-диаграммы со всеми связями классов и их объектов, что от чего нужно наследовать и куда какую ссылку передать(прикинь, что таких классов сотни) - тут и начинаются танцы с бубном...
Никита30 уровень, Днепр
28 августа, 19:07
Лайк статье за эту фразу сразу. Просто жиза (Но не с Java, хотя наверно везде подходит) "Такое наследование не всегда логично. Но если есть только свинья, а очень нужна корова, программист зачастую не может устоять перед желанием сделать «корову» из «свиньи»".
Ivan11 уровень, Нижний Новгород
23 августа, 05:36
"Исходный код класса есть, но ты работаешь в компании, которую могут засудить на пару миллиардов за использование даже 6 строчек чужого кода. А потом она засудит тебя." - абсолютная неисполнимая американоподобная хрень... Тут такой много... но просто американо дешевле... >>> нет явы - ешь питона...