Наследование классов Java

Отношение между классами, при котором характеристики одного класса (суперкласса) передаются другому классу (подклассу) без их повторного описания, называется наследованием.

Подкласс наследует переменные и методы суперкласса, используя ключевое слово extends. Класс может также реализовывать любое число интерфейсов, используя ключевое слово – implements. Подкласс имеет прямой доступ ко всем открытым переменным и методам родительского класса, как будто они находятся в подклассе. Исключение составляют члены класса, помеченные
private (во всех случаях) и «по умолчанию» для подкласса в другом пакете.
В любом случае (даже если ключевое слово extends отсутствует) класс автоматически наследует свойства суперкласса всех классов – класса Object.

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

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

В подклассе можно объявить (переопределить) метод с тем же именем, списком параметров и возвращаемым значением, что и у метода суперкласса.

Способность ссылки динамически определять версию переопределенного метода в зависимости от переданного ссылке в сообщении типа объекта называется полиморфизмом.

Полиморфизм является основой для реализации механизма динамического или «позднего связывания».

В следующем примере переопределяемый метод typeEmployee() находится в двух классах Employee и Manager. В соответствии с принципом полиморфизма вызывается метод, наиболее близкий к текущему объекту.

/* пример # 1 : наследование класса и переопределение метода:

Employee.java: Manager.java: Runner.java */

package chapt04;

public class Employee {// рядовой сотрудник

private int id;

public Employee(int idc) {

super();/* по умолчанию, необязательный явный вызов

конструктора суперкласса */

id = idc;

}

public int getId() {

return id;

}

public void typeEmployee() {

// …

System.out.println("Работник");

}

}

package chapt04;

// сотрудник с проектом, за который он отвечает

public class Manager extends Employee {

private int idProject;

public Manager(int idc, int idp) {

super(idc); /* вызов конструктора суперкласса

с параметром */

idProject = idp;

}

public int getIdProject() {

return idProject;

}

public void typeEmployee() {

// …

System.out.println("Менеджер");

}

}

package chapt04;

public class Runner {

public static void main(String[] args) {

Employee b1 = new Employee(7110);

Employee b2 = new Manager(9251, 31);

b1.typeEmployee();// вызов версии из класса Employee

b2.typeEmployee();// вызов версии из класса Manager

// b2.getIdProject();// ошибка компиляции!!!

((Manager) b2).getIdProject();

Manager b3 = new Manager(9711, 35);

System.out.println(b3.getIdProject());// 35

System.out.println(b3.getId());// 9711

}

}

Объект b1 создается при помощи вызова конструктора класса Employee, и, соответственно, при вызове метода typeEmployee() вызывается версия метода из класса Employee. При создании объекта b2 ссылка типа Employee инициализируется объектом типа Manager. При таком способе инициализации ссылка на суперкласс получает доступ к методам, переопределенным в подклассе.

При объявлении совпадающих по сигнатуре (имя, тип, область видимости) полей в суперклассе и подклассах их значения не переопределяются и никак не пересекаются, то есть существуют в одном объекте независимо друг от друга.
В этом случае задача извлечения требуемого значения определенного поля, принадлежащего классу в цепочке наследования, ложится на программиста. Для
доступа к полям текущего объекта можно использовать указатель this, для
доступа к полям суперкласса – указатель super. Другие возможности рассмотрены в следующем примере:

/* пример # 2 : создание объекта подкласса и доступ к полям с одинаковыми именами: Course.java: BaseCourse.java: Logic.java */

package chapt04;

public class Course {

public int id = 71;

public Course() {

System.out.println("конструктор класса Course");

id = getId();//!!!

System.out.println(" id=" + id);

}

public int getId() {

System.out.println("getId() класса Course");

return id;

}

}

package chapt04;

public class BaseCourse extends Course {

public int id = 90;// так делать не следует!

public BaseCourse() {

System.out.println("конструктор класса BaseCourse");

System.out.println(" id=" + getId());

}

public int getId() {

System.out.println("getId() класса BaseCourse");

return id;

}

}

package chapt04;

public class Logic {

public static void main(String[] args) {

Course objA = new BaseCourse();

BaseCourse objB = new BaseCourse();

System.out.println("objA: id=" + objA.id);

System.out.println("objB: id=" + objB.id);

Course objC = new Course();

}

}

В результате выполнения данного кода последовательно будет выведено:

конструктор класса Course

getId() класса BaseCourse

id=0

конструктор класса BaseCourse

getId() класса BaseCourse

id=90

конструктор класса Course

getId() класса BaseCourse

id=0

конструктор класса BaseCourse

getId() класса BaseCourse

id=90

objA: id=0

objB: id=90

конструктор класса Course

getId() класса Course

id=71

Метод getId() содержится как в классе Course, так и в классе BaseCourse и является переопределенным. При создании объекта класса BaseCourse одним из способов:

Course objA = new BaseCourse();

BaseCourse objB = new BaseCourse();

в любом случае перед вызовом конструктора BaseCourse() вызывается конструктор класса Course. Но так как в обоих случаях создается объект класса BaseCourse, то вызывается метод getId(), объявленный в классе
BaseCourse, который в свою очередь оперирует полем id, еще не проинициализированным для класса BaseCourse. В результате id получит значение по умолчанию, т.е. нуль.

Воспользовавшись преобразованием типов вида ((BaseCourse)objA).id или ((Course)objB).id, легко можно получить доступ к полю id из соответствующего класса.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100