Шаг 37.
Язык программирования Java.
Абстрактные классы

На этом шаге мы рассмотрим абстрактные классы

Чем дальше вверх по иерархии наследования, тем более универсальными и абстрактными становятся классы. В некотором смысле родительские классы, находящиеся на верхней ступени иерархии, становятся настолько абстрактными, что их рассматривают как основу для разработки других классов, а не как классы, позволяющие создавать конкретные объекты. Например, сотрудник - это человек, а человек может быть и студентом. Поэтому расширим иерархию, в которую входит класс Employee, добавив в нее классы Person и Student. Отношения наследования между всеми этими классами показаны на рисунке ниже.


Рис. 1. Иерархия наследования для класса Person и его подклассов

Возникает разумный вопрос: а зачем вообще столь высокий уровень абстракции? Ответ на него простой: существуют определенные свойства, характерные для каждого человека, например, имя. Ведь у сотрудников вообще и у студентов в частности имеются свои имена, и поэтому при внедрении общего суперкласса придется перенести метод getName() на более высокий уровень в иерархии наследования.

Введем новый метод getDescription(), для вывода на экран краткой характеристики человека. Например, этот метод может вывести на экран следующее:

 an employee with a salary of $50,000.00
 a student, ajoring in computer science

Для классов Employee и Student такой метод реализуется довольно просто. Но какие сведения о человеке следует разместить в класс Person? Ведь в нем ничего нет, кроме имени. Разумеется, можно было бы реализовать метод Person.getDescription(), возвращающий пустую строку. Но есть способ намного лучше. От реализации этого метода в классе Person можно вообще отказаться, если воспользоваться ключевым словом abstract, как показано ниже.

 /*Реализация не требуется*/
 public abstract String getDescription();

Класс, содержащий один или несколько абстрактных методов, нужно объявить абстрактным следующим образом:

abstract class Person {
	...
	public abstract String getDescription();
}

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

abstract class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public abstract String getDescription();
}

Некоторые программисты не осознают, что абстрактные классы могут содержать конкретные методы. Общие поля и методы (будь то абстрактные или конкретные) следует всегда перемещать в суперкласс, каким бы он ни был: абстрактным или конкретным.

Абстрактные методы представляют собой прототипы методов, реализованных в подклассах. Расширяя абстрактный класс, можно оставить некоторые или все абстрактные методы неопределенными. При этом подкласс также станет абстрактным. Если даже определить все методы, то и тогда подкласс не перестанет быть абстрактным.

Определим класс Student, расширяющий абстрактный класс Person и реализующий метод getDescription(). Ни один из методов в классе Student не является абстрактным, поэтому нет никакой необходимости объявлять сам класс абстрактным. Но заметим, что класс может быть объявлен абстрактным, даже если он и не содержит ни одного абстрактного метода.

Создать экземпляры абстрактного класса нельзя. Например, приведенное ниже выражение ошибочно. Но можно создать объекты конкретного подкласса:

 new Person("Name");

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

 Person person = new Student("Name", "major");

Здесь person - переменная абстрактного типа Person, ссылающаяся на экземпляр не абстрактного подкласса Student.

Определим конкретный подкласс Student, расширяющий абстрактный класс Person, следующим образом:

class Student extends Person {
    private String major;

    public Student(String name, String major) {
        super(name);
        this.major = major;
    }

    public String getDescription() {
        return "a student majoring in " + major;
    }
}

В этом подклассе определяется метод getDescription(). Все методы из класса Student являются конкретными, а следовательно, класс больше не является абстрактным.

На следующем шаге мы рассмотрим пример использования абстракных классов

Предыдущий шаг Содержание Следующий шаг