Добавил:
ИВТ (советую зайти в "Несортированное") Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
1
Добавлен:
23.11.2024
Размер:
111.62 Кб
Скачать

Наследование.

Одним из самых больших достоинств объектно-ориентированного программирования является возможность такого расширения, или создания подкласса, существующего класса, при котором можно использовать код, написанный для исходного класса.

При расширении класса на его основе создается новый класс, наследующий все поля и методы расширяемого класса. Исходный класс, для которого проводилось расширение, называется суперклассом.

Если подкласс не переопределяет (override) поведение суперкласса, то он наследует все свойства суперкласса. Переопределение же позволяет расширенному классу по-новому реализовать один или несколько унаследованных методов.

Если имя класса родителя не указано, считается, что родителем является класс Object.

В то время как this ссылается на члены текущего объекта, ссылка super используется для ссылок на члены суперкласса. При вызове метода super.method() runtime - система просматривает иерархию классов до первого суперкласса, содержащего method(). Во всех остальных ссылках при вызове метода используется тип объекта, а не тип ссылки на объект.

Все действия по инициализации объектов при наследования классов выполняются этап за этапом в порядке наследования классов.

  • При первом обращении к классу выделяется память под статические поля класса и выполняется их инициализация.

  • Выполняется распределение памяти под создаваемый объект.

  • Выполняются все инициализаторы нестатических полей класса.

  • Выполняется вызов конструктора класса.

При расширении класса необходимо выбрать один из конструкторов суперкласса и вызывать его при конструировании объектов нового класса. Это необходимо для правильного создания части объекта, относящейся к суперклассу, помимо установки правильного исходного состояния для всех добавленных полей.

Конструктор суперкласса может вызываться в конструкторе подкласса посредством явного вызова super(). Если вызов конструктора суперкласса не является самым первым выполняемым оператором в конструкторе нового класса, то перед выполнением последнего автоматически вызывается безаргументный конструктор суперкласса. Если же суперкласс не имеет безаргументного конструктора, вы должны явно вызвать конструктор суперкласса с параметрами. Вызов super() непременно должен быть первым оператором нового конструктора.

Как говорилось ранее, классы, для которых не указан расширяемый класс, являются неявным расширением класса Object. Все ссылки на объекты полиморфно относятся к классу Object, который является базовым классом для всех ссылок, которые могут относиться к объектам любого класса:

Object student = new Child(); // Object = Child

student = “oxford student”; // Object = String

Объекту student вполне законно присваиваются ссылки на объекты Child и String, несмотря на то, что эти классы не имеют между собой ничего общего, за исключением неявного суперкласса Object.

Абстрактные классы

Исключительно полезную концепцию объектно-ориентированного программирования представляют собой абстрактные классы. С их помощью можно объявлять классы, реализованные лишь частично, поручив полную реализацию расширенным классам.

Абстракция оказывается полезной, когда некоторое поведение характерно для большинства или всех объектов данного класса, но некоторые аспекты имеют смысл лишь для ограниченного круга объектов, не составляющих суперкласса. В Java такие классы объявляются с ключевым словом abstract, и каждый метод, не реализованный в классе, также объявляется abstract.

Если все, что вам требуется, — это определить набор методов, которые будут где-то поддерживаться, но не предоставлять для них реализации, то вместо абстрактных классов лучше воспользоваться интерфейсами.

Рассмотрим пример:

// нельзя создать переменную абстрактного класса

public abstract class Human {

private String name;

private int age;

private String sex;

public String GetName() {

return name;

}

public int GetAge() {

return age;

}

public String GetSex() {

return sex;

}

public void SetName(String name) {

this.name = name;

}

public void SetAge(int age) {

this.age = age;

}

public void SetSex(String sex) {

this.sex = sex;

}

protected Human(String name, int age, String sex) {

this.name = name;

this.age = age;

this.sex = sex;

}

// переопределим метод toString

public String toString() {

return name + "\t" + age + "\t" + sex;

}

}

// класс студент расширяет класс Human

public class Student extends Human {

private String patronymic;

public String GetPatronymic() {

return patronymic;

}

public void SettPatronymic(String patronymic) {

this.patronymic = patronymic;

}

public Student(String name, int age, String sex, String Patronymic) {

super(name, age, sex); // вызываем конструктор родительского класса

this.patronymic = patronymic;

}

public String toString() {

// вызываем реализацию родительского класса

return super.toString() + "\t" + patronymic;

}

}

public class Example {

public static void main(String[] args) {

Student student = new Student("Andrey Klochkoff", 15, "male", "Teodorovich");

// распечатаем на экране информацию о студенте

System.out.println(student);

}

}

Если метод объявлен с атрибутом final, это означает, что ни один расширенный класс не сможет переопределить данный метод с целью изменить его поведение. Другими словами, данная версия метода является окончательной.

Подобным образом могут объявляться целые классы:

final class NoExtending {

// ...

}

Класс, помеченный с атрибутом final, не может являться родителем другого класса, а все его методы также неявно являются final.