верно ли что понятие суперкласс является синонимом родительского класса
Суперкласс (информатика)
Суперкласс (информатика)
В информатике суперклассом или родительским классом называют класс, на основе которого создаются другие классы. Классы, полученные на основе суперкласса, называются дочерними классами, производными классами или подклассами.
Суперкласс позволяет создавать обобщенный интерфейс, заключающий в себе настраиваемую функциональность за счет использования виртуальных функций.
Механизм суперклассов широко используется в объектно-ориентированном программировании благодаря возможности повторного использования, что достигается благодаря общим возможностям, инкапсулированным в модульные объекты.
Языки программирования могут поддерживать абстрактные и конкретные суперклассы.
Базовый класс
Базовый класс — это класс, не имеющий суперкласса, и поэтому находится в основании дерева подклассов. Большинство объектно-ориентированных систем программирования обеспечивает библиотеку классов, на основании которых разработчик создает свои собственные. Эти библиотеки зачастую предлагают один или довольно ограниченный набор базовых классов, которые составляют основу бибилотеки.
В случае, когда язык или библиотека имеют лишь один базовый класс, то он именуется высшим типом.
В языке UML класс может иметь собственный набор корневых (root) свойств для обозначения, что это именно базовый класс.
В C++-стиле (который используется в C# и других языках) термин «базовый класс» используется вместо термина «суперкласс».
Разница между родительским классом и суперклассом
Есть ли разница между родительским классом и суперклассом? Является ли суперкласс просто родительским классом, который не наследуется от других классов?
5 ответов
Это скорее разница в терминологии, идея родительских и дочерних классов или суперклассов и подклассов. Кажется, зависит от опыта работы с языком программирования и предметной области приложения, какой из них вы используете, а также от того, когда вы впервые начали заниматься объектно-ориентированным программированием.
В обоих случаях существует класс, родительский класс или суперкласс или базовый класс, от которого производятся другие классы, дочерний класс или подкласс. Дочерний класс или подкласс расширяет родительский класс или суперкласс, добавляя некоторые возможности к существующим возможностям расширяемого класса.
В первые годы объектно-ориентированного программирования терминология сильно изменилась, поскольку в этой области работали разные люди, публиковали статьи и книги и разрабатывали объектно-ориентированные языки. Все это было совершенно новым и захватывающим, и люди пытались решить, какой словарный запас использовать, поэтому они пробовали различные слова и фразы для выражения объектно-ориентированных концепций.
А благодаря ряду языков объектно-ориентированного программирования, которые были разработаны и приобрели популярность, вокруг языка возникло сообщество с определенным словарным запасом. Поэтому старшие и более опытные программисты, которые с самого начала увлеклись объектно-ориентированным программированием, могут называть вещи немного другими.
Родитель и потомок также используются для описания других видов отношений Is-A или Has-A. Например, Родительское окно и Дочернее окно также используются для оконных систем, в которых окно Дочернее содержится в другом окне Родитель. Итак, у родительского окна есть дочернее окно.
В языке Ruby оба понятия означают разные вещи.
По сути, они такие же. В зависимости от языка меняется терминология. Родитель может означать непосредственного родителя, а суперкласс может означать любой из классов-предков. Кроме того, в java есть метод super (), который вызывает родительский конструктор.
Уровни наследования здесь не при чем, не имеет значения, расширяет ли сам суперкласс другой класс.
Я бы сказал, что это то же самое.
Возможно, вы захотите провести различие между прямым и косвенным родительским или суперклассом, но я думаю, что оба термина также недостаточно ясны по этому поводу. Так что, если это то, что вы пытаетесь выразить, лучше скажите прямо.
Кроме того, во многих языках программирования есть ключевое слово «super», используемое для ссылки на (единственный) прямой родительский класс. Но даже там, если вы вызываете «супер» метод, а прямой родитель не реализует его, он также всплывает.
Суперкласс (программирование)
В программировании суперклассом или родительским классом называют класс, на основе которого создаются другие классы. Классы, полученные на основе суперкласса, называются дочерними классами, производными классами или подклассами.
Суперкласс позволяет создавать обобщенный интерфейс, заключающий в себе настраиваемую функциональность за счет использования виртуальных функций.
Механизм суперклассов широко используется в объектно-ориентированном программировании благодаря возможности повторного использования, что достигается благодаря общим возможностям, инкапсулированным в модульные объекты.
Языки программирования могут поддерживать абстрактные и конкретные суперклассы.
Содержание
Базовый класс
Базовый класс — это класс, не имеющий суперкласса, и поэтому находится в основании дерева подклассов. Большинство объектно-ориентированных систем программирования обеспечивает библиотеку классов, на основании которых разработчик создает свои собственные. Эти библиотеки зачастую предлагают один или довольно ограниченный набор базовых классов, которые составляют основу бибилотеки.
В случае, когда язык или библиотека имеют лишь один базовый класс, то он именуется высшим типом.
В языке UML класс может иметь собственный набор корневых (root) свойств для обозначения, что это именно базовый класс.
В C++-стиле (который используется в C# и других языках) термин «базовый класс» используется вместо термина «суперкласс».
Примеры
В нижеследующем примере происходит поиск имён родительских классов для класса Button при помощи метода getSuperclass :
Примечания
См. также
Ссылки
Полезное
Смотреть что такое «Суперкласс (программирование)» в других словарях:
Исключение (программирование) — Обработка исключительных ситуаций (англ. exception handling) механизм языков программирования, предназначенный для описания реакции программы на ошибки времени выполнения и другие возможные проблемы (исключения), которые могут возникнуть при… … Википедия
Подкласс (программирование) — В объектно ориентированном программировании подкласс это класс, наследующий некоторые (или все) свойства от своего суперкласса. Для простоты можно считать подкласс одним из «вариаций» своего суперкласса, как, например, «Мэнкс порода… … Википедия
Objective-C — Класс языка: объектно ориентированный, мультипарадигмальный: рефлексивно ориентированный Появился в: 1986 Автор(ы): Бред Кокс Типизация данных: нестрогая, статическая / динамическая … Википедия
Объектный Си — Objective C Класс языка: объектно ориентированный, мультипарадигмальный: рефлексивно ориентированный Появился в: 1986 г. Автор(ы): Типизация данных: строгая полиморфная, статическая Основные реализации: Apple gcc Испытал … Википедия
Переопределение метода — (англ. Method overriding) в объектно ориентированном программировании одна из возможностей языка программирования, позволяющая подклассу или дочернему классу обеспечивать специфическую реализацию метода, уже реализованного в одном из… … Википедия
JSP — Стиль этой статьи неэнциклопедичен или нарушает нормы русского языка. Статью следует исправить согласно стилистическим правилам Википедии. JSP (JavaServer Pages) технология, позволяющая веб разработчикам легко создавать содержимое, которое… … Википедия
Обработка исключений — Для улучшения этой статьи желательно?: Найти и оформить в виде сносок ссылки на авторитетные источники, подтверждающие написанное. Проставив сноски, внести более точные указания на источники … Википедия
Исключения — Обработка исключительных ситуаций (англ. exception handling) механизм языков программирования, предназначенный для описания реакции программы на ошибки времени выполнения и другие возможные проблемы (исключения), которые могут возникнуть при… … Википедия
Множественное наследование — У этого термина существуют и другие значения, см. Наследование. Множественное наследование свойство, поддерживаемое частью объектно ориентированных языков программирования, когда класс может иметь более одного суперкласса (непосредственного … Википедия
CRC-карта — (англ. Class responsibility collaboration card; рус. карта «Класс Ответственность Кооперация») метод мозгового штурма, предназначенный для проектирования объектно ориентированного программного обеспечения. CRC карты были предложены Уордом… … Википедия
Разница между родительским классом и суперклассом
Есть ли разница между родительским классом и суперклассом? Является ли суперкласс просто родительским классом, который не наследуется от других классов?
ОТВЕТЫ
Ответ 1
Это больше различие в терминологии, идея родительских и дочерних классов или супер и подклассов. Кажется, это зависит от опыта работы с языком программирования и предметной области, от того, какой вы используете, а также от того, когда вы впервые начали заниматься объектно-ориентированным программированием.
В обоих случаях существует класс, родительский класс или суперкласс или базовый класс, из которого происходят другие классы, дочерний класс или подкласс. Дочерний класс или подкласс расширяет родительский класс или суперкласс путем добавления некоторой возможности к существующей возможности расширяемого класса.
В первые годы объектно-ориентированного программирования наблюдался значительный отток терминологии, поскольку в этой области работали разные люди, публиковали статьи и книги и разрабатывали объектно-ориентированные языки. Все это было довольно новым и захватывающим, и люди пытались выбрать правильный словарный запас, чтобы использовать разные слова и фразы для выражения объектно-ориентированных концепций.
А благодаря ряду языков объектно-ориентированного программирования, которые были разработаны и приобрели популярность, вокруг языка возникло сообщество с определенным словарем. Поэтому пожилые и более опытные программисты, которые раньше были объектно-ориентированными, могут назвать вещи немного по-другому.
Родитель и ребенок также используются при описании других видов отношений Is-A или Has-A. Например, родительское окно и дочернее окно также используется для оконных систем, в которых окно, дочернее, содержится в другом окне, родительском. Итак, родительское окно имеет дочернее окно.
Ответ 2
Уровни наследования не имеют никакого отношения к этому, не имеет значения, если сам Суперкласс расширяет другой класс.
Ответ 3
Я бы сказал то же самое.
Возможно, вы захотите провести различие между прямым и косвенным родителем или суперклассом, но я думаю, что оба этих термина также недостаточно ясны. Итак, если это то, что вы пытаетесь выразить, лучше быть явным.
Кроме того, во многих языках программирования ключевое слово «супер» используется для ссылки на единственный (единственный) прямой родительский класс. Но даже там, если вы называете «супер» метод, а прямой родитель не реализует его, он также пузырится вверх.
Ответ 4
Они, по сути, одинаковы. В зависимости от языка изменяется терминология. Родитель может означать непосредственного родителя, в то время как класс Super может означать любой из классов предков. Кроме того, в java существует метод super(), который вызывает родительский конструктор.
Ответ 5
В языке Ruby мы имеем обе концепции, обозначающие разные вещи.
Классы, суперклассы и подклассы
Contents
Наследование
Идея, лежащая в основе наследования, заключается в создании новых классов из уже существующих. Новый класс наследует методы и поля класса-предка. Для адаптации класса-наследника к новым ситуациям, в него добавляются дополнительные поля и методы.
Классы, суперклассы и подклассы
Пример определения класса Manager, порожденного из класса Employee. Для обозначения наследования в Java используется ключевое слово extends:
Механизмы наследования в Java и C++ похожи. В Java вместо символов :: используется ключевое слово extends. Любое наследование в Java является открытым, причем аналога закрытому и защищенному наследованию C++, в Java нет.
Employee является суперклассом. Это не значит, что он имеет превосходство над своим подклассом или обладает более широкими функциональными возможностями. Наоборот, подкласс шире, чем суперкласс. Анализируя код класса Manager, легко увидеть, что он инкапсулирует больше данных и содержит больше методов, чем его суперкласс Employee.
Класс Manager имеет новое поле, для хранения бонусов, и новый метод, позволяющий задавать эту величину.
В этих методах и полях нет ничего особенного. Имея объект Manager, можно просто применять метод setBonus():
Некоторые методы суперкласса не подходят для подкласса Manager. В частности, метод getSalary должен возвращать сумму базовой зарплаты и премии. Следовательно, нужно переопределить метод, т.е. реализовать новый метод, замещающий метод суперкласса:
Метод getSalary() класса Manager не имеет доступа к закрытым полям суперкласса. Несмотря на то, что каждый объект Manager имеет поле salary, метод getSalary() класса Manager не может обратиться к нему непосредственно. Только методы класса Employee имеют доступ к закрытым полям своего класса.
Если методу подкласса Manager нужен доступ к закрытым полям суперкласса Employee, он должен использовать открытый интерфейс суперкласса. Вместо прямого обращения к полю salary нужно вызвать метод getSalary() класса Employee:
Теперь метод getSalary() вызывает сам себя, поскольку в классе Manager есть метод с таким-же именем. Именно его мы пытаемся реализовать. Возникает бесконечная цепочка вызовов одного и того же метода, что приводит к аварийному завершению программы.
Нужно явно указать, что мы хотим вызвать метод getSalary() из суперкласса Employee, а не из текущего класса. Для этой цели используется специальное ключевое слово super. Приведенное ниже выражение вызывает метод getSalary() именно из класса Employee:
Правильный вариант метода getSalary() для класса Manager выглядит так:
Подкласс может добавлять поля, а также добавлять и переопределять методы суперкласса. Причем, при наследовании, ни одно поле или метод из класса не удаляется.
В Java для вызова метода суперкласса используется ключевое слово super. В C++ для этого используют имя суперкласса вместе с оператором разрешения области видимости, например так: Employee::getSalary()
В заключение напишем конструктор класса:
Здесь ключевое слово super имеет другой смысл. Приведенное ниже выражение означает вызов конструктора суперкласса Employee с параметрами n, s, year, month и day:
Поскольку конструктор класса Manager не имеет доступа к закрытым полям класса Employee, он должен инициализировать их, вызывая другой конструктор с помощью ключевого слова super. Вызов, содержащий обращение super, должен быть первым оператором в конструкторе подкласса.
Если конструктор подкласса не обращается к конструктору суперкласса, то автоматически стартует конструктор по умолчанию суперкласса. Если в данной ситуации суперкласс не имеет конструктора по умолчанию, то компилятор сообщит об ошибке.
Ключевое слово this применяется для указания ссылки на неявный параметр, или для вызова другого конструктора того же класса. Аналогично, ключевое слово super используется для вызова: метода суперкласса или конструктора суперкласса. При вызове конструкторов, this и super имеют сходный смысл. Вызов должен быть первым оператором в конструкторе. Параметры вызова конструктора передаются либо конструктору того же класса (this), либо конструктору суперкласса (super).
В C++ вызов конструктора super не применяется. Вместо этого для создания суперкласса используется список инициализации. В C++ конструктор класса Manager выглядел бы так:
После переопределения метода getSalary() в классе Manager, все менеджеры получат премии:
Создадим массив, в котором должны храниться три объекта Employee:
Заполним его объектами Manager и Employee:
Выведем зарплату каждого сотрудника:
В результате выполнения цикла, отображаются строки:
Поскольку staff[1] и staff[2] являются объектами Employee, они выводят базовые зарплаты сотрудников. Объект staff[0] относится к классу Manager, и его метод getSalary() добавляет к базовой зарплате премию.
Обратим особое внимание на вызов:
Переменная е объявлена как Employee. Но фактическим типом объекта, на который она ссылается, может быть как класс Employee (i = [1, 2]), так и класс Manager (i = 0).
Когда e ссылается на объект Employee, выражение e.getSalary() вызывает метод getSalary() класса Employee. Но если переменная e ссылается на объект Manager, вызывается метод getSalary() класса Manager. Виртуальной машине известен фактический тип объекта, на который ссылается переменная, поэтому с вызовом метода проблем не возникает.
В Java нет необходимости объявлять виртуальный метод. Динамическое связывание выполняется по умолчанию. Если требуется запретить переопределение метода, его следует пометить ключевым словом final.
В следующем листинге представлен код, демонстрирующий подсчет заработной платы с использованием объектов Employee и Manager:
Иерархия наследования
Обычно для класса существует несколько цепочек наследования. На основе класса Employee можно создать подкласс Programmer или Secretary, причем они будут независимы друг от друга. Процесс формирования подклассов можно продолжать сколь угодно долго.
В Java множественное наследование не поддерживается. Типичные для множественного наследования задачи решаются в Java с помощью интерфейсов.
Полиморфизм
Например, объект подкласса можно присвоить переменной суперкласса:
Применение этого принципа продемонстрировано в предыдущем листинге.
Переменные staff[0] и boss ссылаются на один и тот же объект. Однако переменная staff[0] рассматривается компилятором только как объект Employee:
Переменная staff[0] объявлена как объект Employee, а метода setBonus() в этом классе нет.
Объект суперкласса может получать ссылки на объекты подклассов, но обратное действие невозможно. Переменным подкласса запрещено получать ссылки на объекты суперкласса:
Причина очевидна: не все сотрудники являются менеджерами. Если переменная m сможет ссылаться на объект Employee, то появится возможность вызвать метод setBonus() для рядового сотрудника, что приведет к ошибке выполнения программы.
Массив ссылок на объекты подкласса можно преобразовать в массив ссылок на объекты суперкласса. Рассмотрим преобразование массива Manager[] в массив ссылок Employee[]:
Каждый менеджер является сотрудником. Поэтому, объект Manager содержит все поля и методы объекта Employee. Однако, ссылка переменных manager и staff на единый массив, может вызвать неприятные последствия. Рассмотрим следующее выражение:
Компилятор допускает подобное действие. Но, staff[0] и manager[0] представляют единую ссылку. Это выглядит, как попытка присвоить переменной, соответствующей менеджеру, ссылку на рядового сотрудника. Становится возможным мызов managers[0].setBonus(1000), что повлечет обращение к несуществующему методу и разрушение содержимого памяти.
Для избежания подобных ситуаций, в массиве запоминается тип элементов и отслеживается допустимость хранящихся ссылок. Например, массив new Manager[10] рассматривается как массив элементов Manager, и попытка записать в него ссылку на объект Employee приводит к исключению ArrayStoreException.
Динамическое связывание
Действия, выполняемые при вызове метода, принадлежащего некоторому объекту:
В подклассе Manager этот метод переопределен следующим образом:
При этом считается, что для методов getBuddy() определены ковариантные возвращаемые типы.
Рассмотрим подробно вызов метода e.getSalary() из предыдущего листинга. Переменная e имеет тип Employee. В этом классе есть только один метод getSalary(), у которого не параметров. Следовательно, в данном случае можно не беспокоиться о разрешении перегрузки.
Поскольку при объявлении метода getSalary() не использовались ключевые слова private, static или final, он связывается динамически. Виртуальная машина создает таблицу методов классов Employee и Manager. Таблица класса Employee показывает, что все методы определены в самом классе.
На самом деле это не совсем так. Как мы увидим позднее, класс Employee имеет суперкласс Object, от которого он наследует больше количество методов; их мы пока будем игнорировать.
Во время выполнения программы вызов метода e.getSalary() осуществляется следующим образом:
При переопределении метода область видимости метода подкласса должна быть не меньше области видимости переопределяемого метода суперкласса. В частности, если при объявлении метода суперкласса использовалось ключевое слово public, метод подкласса также должен быть объявлен как public. Программисты часто ошибаются, забывая указывать спецификатор public при описании метода подкласса. В этих случаях компилятор сообщает о том, что привилегии доступа к данным ограничены.
Предотвращение наследования: терминальные классы и методы
Отдельный метод класса также может быть терминальным. Такой метод не может быть определен в подклассах. Все методы терминального класса автоматически являются терминальными. Пример объявления терминального метода приведен ниже:
Напомним, что с помощью модификатора final могут также описываться поля, являющиеся константами. После создания объекта значение такого поля нельзя изменить. Однако, если класс объявлен как final, терминальными становятся только методы; поля в константы не превращаются.
Существует единственный аргумент в пользу применения ключевого слова final при объявлении метода или класса: это позволяет гарантировать неизменность семантики. Так, например, в классе Calendar методы getTime() и setTime() являются терминальными. Поступая таким образом, разработчики берут на себя ответственность за корректность преобразования содержимого объекта Date в состояние календаря. В подклассах невозможно изменить принцип преобразования. В качестве другого примера можно привести класс String. Создавать подклассы этого класса запрещено. Поэтому если у вас есть переменная типа String, можете быть уверены, что она ссылается именно на строку и ни на какой другой объект.
Некоторые программисты считают, что ключевое слово final надо применять при объявлении всех методов. Исключением являются только те случаи, когда есть веские основания для использования полиморфизма. Действительно, в методах C++ и C# для применения полиморфизма надо принять специальные меры. Может быть, указанное правило слишком жесткое, но, несомненно, что при формировании иерархии классов надо серьезно заботиться об использовании терминальных методов.
На заре развития Java некоторые программисты пытались использовать ключевое слово final для того, чтобы исключить накладные расходы,вызываемые динамическим связыванием. Если метод не переопределяется и размеры его невелики, компилятор применяет процедуру оптимизации, которая состоит в непосредственном включении кода. Например, вызов метода e.getName() заменяется обращением к полю e.name. Такое преобразование достаточно эффективно, так как ветвление программы несовместимо с упреждающей загрузкой команд, применяемой в процессорах. Следует заметить, что если метод getName() будет переопределен, компилятор не сможет непосредственно включить его код, поскольку ему станет неизвестно, какой из методов должен быть вызван в процессе выполнения программы.
Приведение типов
Как известно, в Java тип объектной переменной определяет разновидность объектов, на которые может ссылаться эта переменная. Например, переменная staff[1] ссылается на объект Employee (поэтому она может ссылаться и на объекты Manager).
В процессе работы компилятор проверяет, что происходит в процессе присваивания: сужаются или расширяются возможности объекта, на который указывает переменная. Если переменной суперкласса присваивается объект подкласса, возможности класса сужаются, и компилятор без проблем позволяет программисту сделать это. Если, наоборот, объект суперкласса присваивается переменной подкласса, возможности класса расширяются, поэтому программист должен подтвердить это с помощью обозначения, предназначенного для приведения типов, указав в скобках имя подкласса. Таким образом, виртуальная машина получает возможность контролировать действия программиста в процессе выполнения программы.
Что произойдет, если попытаться осуществить приведение типов вниз по цепочке наследования и попробовать обмануть компилятор?
При выполнении программы система обнаружит несоответствие и сгенерирует исключение. Если его не обработать, работа программы будет прекращена. Итак, перед приведением типов следует проверить его корректность. Для этого нужно использовать оператор instanceof. Например:
В заключение заметим, что компилятор не позволит выполнить некорректное приведение типов. Например, наличие в тексте программы представленной ниже строки приведет к ошибке на этапе компиляции, поскльку класс Date не является подклассом класса Employee.
Таким образом, можно сформулировать основные правила приведения типов:
Если в приведенном ниже выражении x содержит значение null, исключение не будет сгенерировано:
Выражение лишь вернет значение false. Это вполне разумно. Поскольку нулевая ссылка не относится ни к одному объекту, она, очевидно, не относится ни к одному объекту C.
Приведение типов необходимо лишь тогда, когда надо использовать уникальный метод, который есть только в классе Manager, например setBonus(). Если вы, работая с объектом Employee, вдруг захотите вызвать метод setBonus(), задайте себе вопрос: не свидетельствует ли это о недостатках суперкласса? Возможно, следует пересмотреть структуру суперкласса и добавить в него метод setBonus(). Помните, чтобы программа завершила свою работу, достаточно одного-единственного необрабатываемого исключения ClassCastException. В общем, следует по возможности избегать приведения типов и применения оператора instanceof.
В Java для приведения типов используется устаревший синтаксис языка C, однако работает он как безопасная операция динамического приведения типов dynamic_cast языка C++. Например, приведенные ниже две строки кода, написанные на разных языках, почти эквивалентны.
В Java используется комбинация оператора instanceof и оператора приведения типов:
Абстрактные классы
Какие проблемы возникают при таком высоком уровне абстракции? Существуют определенные атрибуты, характерные для каждого человека, например имя. И студенты, и сотрудники имеют имена, и при создании общего суперкласса понадобится перенести метод getName() на более высокий уровень в иерархии наследования.
Добавим теперь новый метод getDescription(), предназначенный для создания краткой характеристики человека, например:
Для классов Employee и Student этот метод реализуется довольно просто. Однако какую информацию можно поместить в класс Person? В нем ничего нет, кроме имени. Разумеется, можно было бы реализовать метод Person.getDescription(), возвращающий пустую строку. Однако есть способ получше. Используя ключевое слово abstract, можно вовсе не реализовывать этот метод:
Для большей ясности класс, содержащий один или несколько абстрактных методов, можно объявить абстрактным:
Кроме абстрактных методов, абстрактные классы могут содержать конкретные данные и методы. Например, класс Person хранит имя человека и содержит конкретный метод, возвращающий это имя:
Многие программисты полагают, что абстрактные классы должны содержать только абстрактные методы. Это далеко не так. В суперклассе следует реализовывать как можно больше функциональных возможностей, независимо от того, абстрактный он или нет. В частности, поля и неабстрактные методы, общие для всех подклассов, нужно помещать в абстрактный суперкласс.
Абстрактные методы представляют собой прототипы методов, реализованных в подклассах. Расширяя абстрактный класс, можно оставить некоторые или все абстрактные методы неопределенными. При этом подкласс станет абстрактным. Кроме того, можно определить все методы. Тогда подкласс не будет абстрактным.
Определим класс Student, расширяющий абстрактный класс Person и реализующий метод getDescription(). Поскольку ни один из методов в классе Student не является абстрактным, нет никакой необходимости объявлять сам класс абстрактным.
Класс может быть объявлен абстрактным, даже если он не содержит ни одного абстрактного метода.
Создать объекты абстрактного класса невозможно. Например, приведенное ниже выражение ошибочно:
Однако можно создать объекты конкретного подкласса.
Заметим, что можно создавать объектные переменные абстрактных классов, однако такие переменные должны ссылаться на объект неабстрактного класса. Рассмотрим следующую строку кода:
Класс в C++ является абстрактным, если он содержит хотя бы одну чисто виртуальную функцию. В C++ нет специального ключевого слова, означающего абстрактные классы.
Определим конкретный подкласс Student, расширяющий аьстрактный класс Person.
В этом подклассе определяется метод getDescription(). Следовательно, все методы в классе Student являются конкретными, и класс больше не является абстрактным.
В листинге, представленном ниже, определен абстрактный суперкласс Person и два конкретных подкласса Employee и Student. Заполним массив типа Person ссылками на экземпляры классов Employee и Student.
Затем выведем имена и характеристики этих объектов.
Некоторых читателей присутствие вызова p.getDescription() может озадачить. Не относится и он к неопределенному методу? Учтите, что переменная p никогда не сылается ни на один объект абстрактного класса Person, поскольку создать такой объект попросту невозможно. Переменная p всегда ссылается на объект конкретного подкласса, например Employee или Student. Для этих объектов метод getDescription() определен.
Можно ли пропустить в классе Person все абстрактные методы и определить метод getDescription() в подклассах Employee и Student? Это не будет ошибкой, но тогда метод getDescription() нельзя будет вызвать с помощью переменной p. Компилятор гарантирует, что вызываются только методы, определенные в классе.
Абстрактные методы представляют собой важное понятие Java. В основном они применяются при создании интерфейсов, которые будут детально рассмотрены в следующих разделах.
Содержимое файла PersonTest.java
Защищенный доступ
Иногда нужно ограничивать доступ к некоторому методу и открывать его лишь для подклассов. Гораздо реже возникает необходимость предоставлять методам подкласса доступ к полям суперкласса. В этом случае элемент класса объявляется защищенным с помощью ключевого слова protected. Например, если в суперклассе Employee поле hireDay объявлено защищенным, а не закрытым, методы подкласса Manager смогут обращаться к нему непосредственно.
Однако методы класса Manager имеют доступ лишь к полям hireDay, принадлежащим объектам самого класса Manager, но не класса Employee. Это ограничение введено для того, чтобы программисты не могли злоупотреблять механизмом защищенного доступа и создавать подклассы лишь для получения доступа к защищенным полям.
На практике пользоваться атрибутом protected нужно очень осторожно. Предположим, что ваш класс, в котором есть защищенные поля, используется другими разработчиками. Без вашего ведома другие программисты могут создавать подклассы вашего класса и тем самым получать доступ к защищенным полям. Теперь вы уже не можете изменять реализацию своего класса, не уведомив других программистов. Это противоречит принципам ООП, поощряющего инкапсуляцию данных.
В качестве примера защищенного метода можно привести clone() класса Object.
В Java защищенные элементы доступны из всех подклассов, а также из других классов того же пакета. Этим Java отличается от C++, в котором ключевое слово protected имеет несколько иной смысл. Таким образом, в Java ограничения на доступ к защищенным элементам шире, чем в C++.
Итак, в Java есть четыре модификатора доступа, управляющих областью видимости: