--- title: Inheritance localeTitle: наследование --- # наследование Наследование Java относится к способности класса Java `inherit` свойства другого класса. Подумайте об этом, как о ребенке, наследующем свойства от своих родителей, концепция очень похожа на это. В Java lingo он также называется _расширением_ класса. Некоторые простые вещи, которые нужно запомнить: * Класс, который распространяется или наследуется, называется **подклассом** * Класс, который расширяется или унаследован, называется **суперклассом** Таким образом, наследование дает Java отличную возможность _повторного использования_ кода или обмена кодами между классами! Давайте опишем его с классическим примером класса `Vehicle` класса `Car` : ```java public class Vehicle { public void start() { // starting the engine } public void stop() { // stopping the engine } } public class Car extends Vehicle { int numberOfSeats = 4; public int getNumberOfSeats() { return numberOfSeats; } } ``` Здесь мы можем увидеть класс `Car` наследующий свойства класса `Vehicle` . Таким образом, нам не нужно писать один и тот же код для методов `start()` и `stop()` для `Car` , так как эти свойства доступны из его родительского или суперкласса. Поэтому объекты, созданные из класса `Car` , _также_ будут обладать этими свойствами! ```java Car tesla = new Car(); tesla.start(); tesla.stop(); ``` ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [Код запуска](https://repl.it/CJXz/0) Но имеет ли родительский класс методы для ребенка? Нет, нет. Следовательно, всякий раз, когда вам нужно разделить некоторые общие части кода между несколькими классами, всегда полезно иметь родительский класс, а затем распространять этот класс всякий раз, когда это необходимо! Сокращает количество строк кода, делает код модульным и упрощает тестирование. ## Что можно унаследовать? * Все `protected` и `public` поля и методы от родительских ## Что нельзя унаследовать? * `private` поля и методы * Конструкторы. Хотя конструктор подкласса _должен_ вызывать конструктор суперкласса, если он определен (подробнее об этом позже!) * Несколько классов. Java поддерживает только **одно наследование** , то есть вы можете наследовать только один класс за раз. * Поля. Отдельные поля класса не могут быть переопределены подклассом. ## Тип литья и ссылки В Java можно ссылаться на подкласс как _экземпляр_ его суперкласса. Он называется _полиморфизмом_ в объектно-ориентированном программировании (ООП), возможностью для объекта принимать различные формы. Например, объект класса `Car` можно называть экземпляром класса `Vehicle` следующим образом: ```java Vehicle car = new Car(); ``` Хотя, наоборот, невозможно: ```java Car car = new Vehicle(); // ERROR ``` ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [Код запуска](https://repl.it/CJYB/0) Поскольку вы можете ссылаться на подкласс Java как экземпляр суперкласса, вы можете легко передать экземпляр объекта подкласса в экземпляр суперкласса. Можно включить объект суперкласса в тип подкласса, но _только если объект действительно является экземпляром подкласса_ . Поэтому имейте это в виду: ```java Car car = new Car(); Vehicle vehicle = car; // upcasting Car car2 = (Car)vechile; //downcasting Bike bike = new Bike(); // say Bike is also a subclass of Vehicle Vehicle v = bike; // upcasting, no problem here. Car car3 = (Car)bike; // Compilation Error : as bike is NOT a instance of Car ``` ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [Код запуска](https://repl.it/CJYM/0) Теперь вы знаете, как делиться кодом через отношения родитель-ребенок. Но что, если вам не нравится реализация определенного метода в дочернем классе и хотите написать для него новый? Что вы делаете тогда? ## Переопределите это! Java позволяет вам _переопределять_ или переопределять методы, определенные в суперклассе. Например, ваш класс `Car` имеет другую реализацию `start()` чем исходный `Vehicle` , поэтому вы делаете это: ```java public class Vehicle { public void start() { System.out.println("Vehicle start code"); } } public class Car extends Vehicle { public void start() { System.out.println("Car start code"); } } Car car = new Car(); car.start(); // "Car start code" ``` ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [Код запуска](https://repl.it/CJYZ/1) Таким образом, довольно просто переопределить методы в подклассе. Хотя, есть _улов_ . Только этот метод суперкласса с той _же сигнатурой метода,_ что и метод подкласса, будет переопределен. Это означает, что определение метода подкласса должно иметь одно и то же имя, одинаковое количество и тип параметров и в той же последовательности. Таким образом, `public void start(String key)` не будет отменять `public void start()` . **Примечания** : * Вы не можете переопределить частные методы суперкласса. (Совершенно очевидно, не так ли?) * Что делать, если метод суперкласса, который вы переопределяете в подклассе, внезапно исчезает или меняются методы? Это не сработает во время выполнения! Поэтому Java предоставляет вам замечательную аннотацию `@Override` которую вы можете разместить над методом подкласса, который будет предупреждать компилятор об этих инцидентах! Аннотации на Java - хорошая практика кодирования, но они не являются необходимостью. Компилятор достаточно умен, чтобы разобраться в себе. В отличие от других языков ООП, аннотации в Java не обязательно изменят метод или добавляют дополнительные функции. ## Как назвать методы суперкласса? Забавно, что вы спрашиваете об этом! Просто используйте ключевое слово `super` : ```java public class Vehicle() { public void start() { System.out.println("Vehicle start code"); } } public class Car extends Vehicle { public void run() { super.start(); } } Car car = new Car(); car.run(); // "Vehicle start code" ``` ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [Код запуска](https://repl.it/CJY4/0) **NB** : Хотя вы можете вызвать родительский метод, используя `super` , вы не можете подойти к иерархии наследования с помощью прикованных `super` вызовов. ## Как узнать тип класса? Использование ключевого слова `instanceof` . Обладая множеством классов и подклассов, было бы немного смутно знать, какой класс является подклассом, из которых один во время выполнения. Таким образом, мы можем использовать `instanceof` для определения того, является ли объект экземпляром класса, экземпляром подкласса или экземпляром интерфейса. ```java Car car = new Car(); boolean flag = car instanceof Vehicle; // true in this case! ``` ## Конструкторы и наследование Как упоминалось ранее, конструкторы не могут быть непосредственно унаследованы подклассом. Хотя подкласс _требуется_ для вызова конструктора своего родителя в качестве [первой операции](http://stackoverflow.com/questions/1168345/why-does-this-and-super-have-to-be-the-first-statement-in-a-constructor) в своем собственном конструкторе. Как? Вы догадались, используя `super` : ```java public class Vehicle { public Vehicle() { // constructor } public void start() { System.out.println("Vehicle start code"); } } public class Car extends Vehicle { public Car() { super(); } public void run() { super.start(); } } ``` ![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [Код запуска](https://repl.it/CJY8/0) Помните, что если суперкласс не имеет определенных конструкторов, вам не нужно его явно указывать в подклассе. Java обрабатывает это внутренне для вас! Вызов в `super` выполняется в случае, когда суперкласс должен вызываться с любым другим конструктором, отличным от _конструктора_ по _умолчанию_ . Если никакие другие конструкторы не определены, то Java вызывает конструктор суперкласса по умолчанию ( _даже если он явно не определен_ ). Поздравляю, теперь вы все знаете о Наследии! Подробнее о расширенных способах наследования вещей в абстрактных классах и [интерфейсах](//forum.freecodecamp.com/t/java-docs-interfaces) !