что такое ооп java
Что такое ооп java
Основная цель использования данной концепции — это уменьшение сложности компонентов программы за счет скрытия от программиста, использующего эти компоненты, ненужных ему подробностей. Это позволяет реализовать более сложную логику поверх предоставленной абстракции, не вдаваясь в подробности ее реализации.
Приготовление кофе с помощью кофемашины является хорошим примером абстракции. Все, что нам надо знать, что бы ей пользоваться: как налить воды, засыпать кофейные зерна, включить и выбрать вид кофе, который хотим получить. А, как машина будет варить кофе — нам знать не нужно.
В данном примере кофемашина представляет собой абстракцию, которая от нас скрывает все подробности варки кофе. Нам лишь остается просто взаимодействовать с простым интерфейсом, который не требует от нас каких-либо знаний о внутренней реализации машины.
Этот же подход можно использовать и в объектно-ориентированных языках программирования, таких как Java.
Полиморфизм предоставляет возможность единообразно обрабатывать объекты с различной реализацией при условии наличия у них общего интерфейса или класса. По-простому: способность вызывать нужные методы у объектов, имеющие разные типы (но находящиеся в одной иерархии). При этом происходит автоматический выбор нужного метода в зависимости от типа объекта.
Рассмотрим примеры полиморфизма в Java: переопределение и перегрузка методов.
В случае с переопределением метода, дочерний класс, используя концепцию полиморфизма, может изменить (переопределить) поведение метода родительского класса. Это позволяет программисту по разному использовать один и тот же метод, определяя поведение из контекста вызова (вызывается метод из класса предка или класса наследника).
В случае же с перегрузкой, метод может проявлять различное поведение в зависимости от того, какие аргументы он принимает. В данном случае контекст вызова определяется набором параметров метода.
ООП в Java: четыре принципа с примерами
Объектно-ориентированное программирование (ООП) — это методология программирования с использованием объектов и классов.
Объект характеризует состояние и поведение. Например, у кота есть такие свойства, как имя, порода, цвет. Представим, что они отражают его состояние. Кот может мурчать, спать, охотиться, есть и так далее — это проявления его поведения.
С помощью таких характеристик можно описать любого кота. Шаблон, в котором описаны общие черты и действия похожих друг на друга объектов, называется классом. А объект — это конкретный экземпляр класса. Например, рыжий короткошерстный кот Альбатрос и серый пушистый кот Петька — это объекты класса «кот».
В классах Java состояние представлено в виде полей, а поведение — в виде методов.
Содержание статьи:
Принципы ООП
Объектно-ориентированное программирование опирается на четыре принципа:
Рассмотрим эти принципы подробнее.
Наследование
Наследование позволяет использовать код повторно. Это достигается за счет того, что в одном классе содержатся свойства и методы, общие для более конкретных классов. Класс, от которого наследуются свойства и методы, называется суперклассом (родительским классом). Классы, которые наследуют их, называются подклассами (дочерними классами). Таким образом создается иерархия классов.
На вершине иерархии находится базовый класс. Он не является подклассом, то есть не наследует свойств и методов от других классов. На его основе создаются остальные классы иерархии.
Создадим базовый класс Animal, который описывает животное.
Допустим, у животного есть имя и оно издает какой-то звук. Определим имя и звук как строковые поля.
Ключевое слово private — это модификатор доступа, который означает, что поле будет доступно только в данном классе и его подклассах. Таким образом мы запрещаем изменение значений двух полей этого класса извне.
Чтобы создать экземпляр класса (объект) и задать начальные значения полей, объявим общедоступный конструктор, используя модификатор доступа public. Он позволит обращаться к конструктору извне.
Ключевое слово this — это ссылка на создаваемый объект. Для обращения к полю внутри объекта используется синтаксис:
В этом конструкторе мы присваиваем полям объекта значения, переданные в формальных параметрах.
На данном этапе уже реализовано состояние объекта. Теперь реализуем его поведение.
Мы объявили общедоступный метод speak(), в котором на консоли выводится значение поля voice.
Создадим класс Cat, который будет представлять кота и унаследует от класса Animal его свойства и поведение. Для создания подкласса используется ключевое слово extends.
Благодаря наследованию нам не пришлось еще раз писать код, чтобы дать коту имя и указать звук, который он издает. Имя конкретного кота мы заранее не знаем, но знаем, что коты мяукают. Поэтому конструктор этого класса принимает только один формальный параметр name.
Для обращения к суперклассу из подкласса используется ключевое слово super. В данном случае мы вызываем конструктор суперкласса и передаем ему формальный параметр name и литерал meow. Конструктор суперкласса присваивает унаследованным переменным объекта переданные значения.
Теперь мы можем создать экземпляр класса Cat и воспользоваться методом speak(), унаследованным от суперкласса, чтобы «услышать», как мяукает кот.
В языке Java все (точнее, почти все) является объектом. Поэтому мы создаем класс Main с методом main, в котором содержатся инструкции программы. В нем мы объявляем переменную класса Cat для создания объекта. Чтобы инициализировать его, обращаемся к конструктору, используя ключевое слово new, и задаем имя питомца:
Полный код будет выглядеть так:
Абстракция
Для решения сложной задачи нужно разделить ее на части, с которыми удобно работать. Некоторые части могут быть похожими друг на друга, то есть иметь общие признаки. Например, у сотрудника компании и у клиента есть имя, фамилия, адрес. Эти общие свойства можно вынести в отдельный более абстрактный класс.
При моделировании реальных объектов совсем необязательно учитывать все их характеристики. Как правило, для решения определенной задачи бывает достаточно лишь нескольких. Поэтому в определении клиента и сотрудника неважен рост или цвет волос (если только этого не требует задача).
Создадим класс Person и определим в нем общие характеристики.
Унаследуем от него классы Customer и Employee. Добавим для клиента номер банковского счета, а для сотрудника — размер зарплаты.
Так, мы избавились от повторного написания кода, выделив общие признаки в суперкласс. Рабочий пример выглядит так:
Инкапсуляция
Инкапсуляция дает возможность предоставить пользователю методы, которые нужны для работы с объектами, и скрыть от него детали их реализации. Площадь треугольника и площадь прямоугольника вычисляются по разным формулам. Несмотря на это, можно объявить для обеих фигур метод square, который получит разные реализации.
Площадь прямоугольника равна произведению длин его сторон. Площадь треугольника по сторонам можно вычислить по формуле Герона. Создадим абстрактный класс Area, который будет представлять геометрическую фигуру.
Абстрактный класс, как и его абстрактный метод, объявляются с помощью ключевого слова abstract. Абстрактный метод не имеет реализации, он лишь объявлен в коде класса.
Создадим производные классы Rectangle и Triangle.
В этих классах объявлены стороны и переопределен унаследованный метод area().
Стороны объявлены с использованием модификатора final, который означает, что значение данного поля — это константа, и поэтому не может быть изменено во время выполнения программы. Если объявить класс как final, то он не сможет иметь подклассов.
Подклассы могут переопределять методы суперкласса с использованием аннотации @Override. Как видим, в переопределенных методах, в отличие от абстрактного, содержится код вычисления площади.
Для вычисления площади треугольника мы используем статический метод sqrt() класса Math. Чтобы воспользоваться таким методом в программе, его нужно импортировать:
Полный код будет выглядеть так:
Хоть площадь этих фигур определяется по разным формулам, мы просто вызываем метод area(), не заботясь о том, как производятся вычисления.
Полиморфизм
Используя полиморфизм, можно обращаться к методам экземпляров суперкласса и его подклассов, как к методам одинаковых объектов. Допустим, существует два музыканта: клавишник и гитарист. Оба они могут играть, но играют на разных инструментах.
Рассмотрим полный пример кода:
Обратите внимание, что в определении суперкласса мы используем модификатор protected для поля name. Этот модификатор позволяет обращаться к нему не только из данного класса, но и из его подклассов. Прямой доступ извне по-прежнему закрыт.
В методе Main мы создаем список объектов класса Musician, в котором могут находиться и экземпляры унаследованных от него классов:
Затем в цикле мы перечисляем музыкантов и вызываем для каждого из них метод play(). Поскольку этот метод реализован во всех классах, не приходится заботиться о том, на чем именно играет каждый музыкант, и писать код вызова метода для каждого из них отдельно.
Причины появления ООП
По мере того, как совершенствовались компьютеры, требовалось создавать все больше функций. Разобраться в коде и разделить задачу на части становилось труднее и труднее.
Объектно-ориентированное программирование было создано как ответ на эти трудности. Оно позволило объединить связанные участки кода и отделить их от тех участков, с которыми они были связаны слабо.
В результате вместо огромного количества процедур и переменных требовалось помнить лишь те, которые нужны для применения объекта (интерфейс). Остальная часть его реализации была скрыта.
Если требовалось внести изменения или улучшить код, это стало происходить незаметно для пользователя, потому что интерфейс не менялся. Кроме того, наследование давало возможность повторно использовать код.
ООП упрощает понимание кода и позволяет экономить много времени при его написании.
Что такое ооп java
Объектно-ориентированное программирование (ООП) — методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
Программа считается объектно-ориентированной, только если выполнены все три указанных требования. В частности, программирование, не использующее наследование, называется не объектно-ориентированным, а программированием с помощью абстрактных типов данных.
Основные принцыпы ООП.
Это единственно верный порядок парадигм ООП, так как каждая последующая использует предыдущие.
Что такое «инкапсуляция»?
Инкапсуляция – это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали реализации от пользователя, открыв только то, что необходимо при последующем использовании.
Цель инкапсуляции — уйти от зависимости внешнего интерфейса класса (то, что могут использовать другие классы) от реализации. Чтобы малейшее изменение в классе не влекло за собой изменение внешнего поведения класса.
Что такое «наследование»?
Наследование – это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью.
Класс, от которого производится наследование, называется предком, базовым или родительским. Новый класс – потомком, наследником или производным классом.
Полиморфизм – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.
Полиморфная переменная, это переменная, которая может принимать значения разных типов, а полиморфная функция, это функция у которой хотя бы один аргумент является полиморфной переменной. Выделяют два вида полиморфных функций:
Абстрагирование – это способ выделить набор общих характеристик объекта, исключая из рассмотрения частные и незначимые. Соответственно, абстракция – это набор всех таких характеристик.
Что представляет собой «обмен сообщениями»?
Объекты взаимодействуют, посылая и получая сообщения. Сообщение — это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия. В ООП посылка сообщения (вызов метода) — это единственный путь передать управление объекту. Если объект должен «отвечать» на это сообщение, то у него должна иметься соответствующий данному сообщению метод. Так же объекты, используя свои методы, могут и сами посылать сообщения другим объектам. Обмен сообщениями реализуется с помощью динамических вызовов, что приводит к чрезвычайно позднему связыванию (extreme late binding).
Расскажите про основные понятия ООП: «класс», «объект», «интерфейс».
Класс – это способ описания сущности, определяющий состояние и поведение, зависящее от этого состояния, а также правила для взаимодействия с данной сущностью (контракт).
С точки зрения программирования класс можно рассматривать как набор данных (полей, атрибутов, членов класса) и функций для работы с ними (методов).
С точки зрения структуры программы, класс является сложным типом данных.
Объект (экземпляр) – это отдельный представитель класса, имеющий конкретное состояние и поведение, полностью определяемое классом. Каждый объект имеет конкретные значения атрибутов и методы, работающие с этими значениями на основе правил, заданных в классе.
Интерфейс – это набор методов класса, доступных для использования. Интерфейсом класса будет являться набор всех его публичных методов в совокупности с набором публичных атрибутов. По сути, интерфейс специфицирует класс, чётко определяя все возможные действия над ним.
В чем заключаются преимущества и недостатки объектно-ориентированного подхода в программировании?
Что подразумевают в плане принципов ООП выражения «является» и «имеет»?
«является» подразумевает наследование. «имеет» подразумевает ассоциацию (агрегацию или композицию).
В чем разница между композицией и агрегацией?
Ассоциация обозначает связь между объектами. Композиция и агрегация — частные случаи ассоциации «часть-целое».
Агрегация предполагает, что объекты связаны взаимоотношением «part-of» (часть). Композиция более строгий вариант агрегации. Дополнительно к требованию «part-of» накладывается условие, что экземпляр «части» может входить только в одно целое (или никуда не входить), в то время как в случае агрегации экземпляр «части» может входить в несколько целых.
Что такое статическое и динамическое связывание?
Присоединение вызова метода к телу метода называется связыванием. Если связывание проводится компилятором (компоновщиком) перед запуском программы, то оно называется статическим или ранним связыванием (early binding).
В свою очередь, позднее связывание (late binding) это связывание, проводимое непосредственно во время выполнения программы, в зависимости от типа объекта. Позднее связывание также называют динамическим (dynamic) или связыванием на стадии выполнения (runtime binding). В языках, реализующих позднее связывание, должен существовать механизм определения фактического типа объекта во время работы программы, для вызова подходящего метода. Иначе говоря, компилятор не знает тип объекта, но механизм вызова методов определяет его и вызывает соответствующее тело метода. Механизм позднего связывания зависит от конкретного языка, но нетрудно предположить, что для его реализации в объекты должна включаться какая-то дополнительная информация.
Для всех методов Java используется механизм позднего (динамического) связывания, если только метод не был объявлен как final (приватные методы являются final по умолчанию).
Что такое концепции ООП в Java? Как они работают и многое другое
ООП — одна из самых фундаментальных концепций программирования. Давайте рассмотрим четыре основных концепции ООП в Java и обсудим, как каждая из них работает.
Java является одним из многих языков программирования и технологий, поддерживаемых ведущими инструментами Netreo в, Retrace и префиксов. В Netreo мы стремимся помочь разработчикам стать лучше. Давайте взглянем на некоторые из основополагающих концепций языка программирования Java с учебником по концепциям ООП в Java.
Определение концепций ООП в Java
Основные идеи объектно-ориентированного программирования Java, концепции ООП включают абстракцию, инкапсуляцию, наследование и полиморфизм. По сути, концепции Java OOP позволяют нам создавать рабочие методы и переменные, а затем повторно использовать их все или часть без ущерба для безопасности. Понимание концепций ООП — ключ к пониманию того, как работает Java.
Java определяет концепции ООП следующим образом:
Как работают концепции ООП в Java
Концепции ООП в Java работают, позволяя программистам создавать компоненты, которые можно повторно использовать различными способами, сохраняя при этом безопасность.
Как работает абстракция
Абстракция позволяет программистам создавать полезные и повторно используемые инструменты. Например, программист может создать несколько различных типов объектов, которые могут быть переменными, функциями или структурами данных. Программисты также могут создавать различные классы объектов как способы определения объектов.
Например, класс переменной может быть адресом. Класс может указать, что каждый объект адреса должен иметь имя, улицу, город и почтовый индекс. Объектами в этом случае могут быть адреса сотрудников, адреса клиентов или адреса поставщиков.
Как работает инкапсуляция
Инкапсуляция позволяет нам повторно использовать функциональность без ущерба для безопасности. Это мощная, экономящая время концепция ООП в Java. Например, мы можем создать фрагмент кода, который вызывает определенные данные из базы данных. Может быть полезно повторно использовать этот код с другими базами данных или процессами. Инкапсуляция позволяет нам делать это, сохраняя при этом конфиденциальность исходных данных. Это также позволяет нам изменять наш исходный код, не нарушая его для других, которые тем временем приняли его.
Как работает наследование
Наследование — это еще одна экономящая труд концепция Java ООП, которая работает, позволяя новому классу перенимать свойства другого. Мы называем наследующий класс подклассом или дочерним классом. Исходный класс часто называют родительским. Мы используем ключевое слово extends для определения нового класса, который наследует свойства старого класса.
Как работает полиморфизм
Полиморфизм в Java работает, используя ссылку на родительский класс для воздействия на объект в дочернем классе. Мы могли бы создать класс под названием «лошадь», расширив класс «животное». Этот класс может также реализовывать класс «профессиональных гонок». Класс «лошадь» является «полиморфным», поскольку он наследует атрибуты как класса «животное», так и класса «профессиональные скачки».
Еще два примера полиморфизма в Java — это переопределение метода и перегрузка метода.
При переопределении метода дочерний класс может использовать концепцию полиморфизма ООП для переопределения метода своего родительского класса. Это позволяет программисту использовать один метод по-разному в зависимости от того, вызывается ли он объектом родительского класса или объектом дочернего класса.
При перегрузке метода один метод может выполнять разные функции в зависимости от контекста, в котором он вызывается. Это означает, что одно имя метода может работать по-разному в зависимости от того, какие аргументы ему переданы.
Примеры концепций ООП в Java
Теперь, когда мы объяснили основополагающие концепции ООП в Java, давайте рассмотрим несколько распространенных примеров.
Краткий пример инкапсуляции в Java
В приведенном ниже примере инкапсуляция демонстрируется как концепция ООП в Java. Здесь переменная name остается закрытой или инкапсулированной.
Пример наследования в Java
В Java довольно просто добиться наследования как концепции ООП. Наследование может быть таким же простым, как использование ключевого слова extends :
Краткий пример полиморфизма в Java
В приведенном ниже примере полиморфизма как концепции ООП в Java у нас есть два класса: Person и Employee. Класс Employee наследуется от класса Person с помощью ключевого слова extends. Здесь дочерний класс переопределяет родительский класс.
Лучшие практики для концепций ООП в Java
Цель концепций ООП в Java — сэкономить время без ущерба для безопасности и простоты использования. Все следующие передовые практики направлены на достижение этой главной цели.
Эти концепции и передовые методы хороши ровно настолько, насколько хороши разработчики, которые их реализуют. Чтобы сделать вашу работу лучше, вам понадобятся инструменты повышения производительности для улучшения вашего программирования на Java.
Что такое ООП и с чем его едят?
Из своего опыта могу сказать, что всегда считал что понимал ООП, что же тут такого то — полиморфизм, инкапсуляция и наследование, но вот когда дошло до дела, то туговато пришлось. Хочу разложить всё по полочкам чтобы никто не наступил на мои грабли в будущем 🙂
Шаг 1.
Немного теории:
Объектно-ориентированное программирование (в дальнейшем ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов.
В центре ООП находится понятие объекта.
Объект — это сущность, экземпляр класса, которой можно посылать сообщения и которая может на них реагировать, используя свои данные. Данные объекта скрыты от остальной программы. Сокрытие данных называется инкапсуляцией.
Наличие инкапсуляции достаточно для объектности языка программирования, но ещё не означает его объектной ориентированности — для этого требуется наличие наследования.
Но даже наличие инкапсуляции и наследования не делает язык программирования в полной мере объектным с точки зрения ООП. Основные преимущества ООП проявляются только в том случае, когда в языке программирования реализован полиморфизм, то есть возможность объектов с одинаковой спецификацией иметь различную реализацию.
Хочу выделить что очень часто натыкаюсь на мнение, что в ООП стоит выделять еще одну немаловажную характеристику — абстракцию. Официально её не вносили в обязательные черты ООП, но списывать ее со счетов не стоит.
Абстрагирование — это способ выделить набор значимых характеристик объекта, исключая из рассмотрения не значимые Соответственно, абстракция — это набор всех таких характеристик.
Инкапсуляция — это свойство системы, позволяющее объединить данные и методы, работающие с ними в классе, и скрыть детали реализации от пользователя.
Наследование — это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью. Класс, от которого производится наследование, называется базовым, родительским или суперклассом. Новый класс — потомком, наследником или производным классом
Полиморфизм — это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.
Шаг 2.
Инкапсуляция.
Инкапсуляция позволит скрыть детали реализации, и открыть только то что необходимо в последующем использовании. Другими словами инкапсуляция – это механизм контроля доступа.
Зачем же это нужно?
Думаю, вам бы не хотелось, чтобы кто-то, что-то изменял в написанной вами библиотеки.
И если это опытный программист, то это простить еще можно, но все равно не приятно, а вот если это начинающий или не осторожный который с легкой руки задумает изменить код, да ещё не в ту степь, нам ведь такого не хочется! Чтобы обезопасить себя от таких поступков, существует инкапсуляция.
Цель инкапсуляции – уйти от зависимости внешнего интерфейса класса (то, что могут использовать другие классы) от реализации. Чтобы малейшее изменение в классе не влекло за собой изменение внешнего поведения класса. Давайте рассмотрим, как ею пользоваться.
Существует 4 вида модификаторов доступа: public, protected, private и default.
Public – уровень предполагает доступ к компоненту с этим модификатором из экземпляра любого класса и любого пакета.
Protected – уровень предполагает доступ к компоненту с этим модификатором из экземпляров родного класса и классов-потомков, независимо от того, в каком пакете они находятся.
Default – уровень предполагает доступ к компоненту с этим модификатором из экземпляров любых классов, находящихся в одном пакете с этим классом.
Private – уровень предполагает доступ к компоненту с этим модификатором только из этого класса.
public String name; — имя, которое доступное из любого места в приложении.
protected String surname; — фамилия доступна из родного класса и потомков.
private int age; — возраст доступен только в рамках класса Human.
int birthdayYear; — хоть не указывается явный модификатор доступа, система понимает его как default, год рождения будет доступен всему пакету, в котором находится класс Human.
Для разных структурных элементов класса предусмотрена возможность применять только определенные уровни модификаторов доступа.
Для класса — только public и default.
Для атрибутов класса — все 4 вида.
Для конструкторов — все 4 вида.
Для методов — все 4 вида.
Шаг 3.
Наслед ование.
Наследование — это процесс, посредством которого один объект может приобретать свойства другого. Точнее, объект может наследовать основные свойства другого объекта и добавлять к ним черты, характерные только для него.
Наследование является важным, поскольку оно позволяет поддерживать концепцию иерархии классов (hierarchical classification). Применение иерархии классов делает управляемыми большие потоки информации.
Разберем этот механизм на классическом примере: Геометрические фигуры.
У нас есть интерфейс Figure:
Интерфейс (более детально будут рассмотрены в скором будущем) — нам говорит, как должен выглядеть класс, какие методы в себе содержать, какими переменными и типами данных манипулировать. Сам интерфейс не реализует методы, а создает как бы скелет для класса, который будет расширять этот интерфейс. Есть класс Figure, который расширяет интерфейс Figure:
В этом классе мы реализуем все методы интерфейса Figure.
public class Figure implements devcolibri.com.oop.inheritance.interfaces.Figure — с помощью ключевого слова implements мы перенимаем методы интерфейса Figure для реализации.
Важно: в классе должны быть все методы интерфейса, даже если некоторые еще не реализованы, в противном случае компилятор будет выдавать ошибку и просить подключить все методы. Тело методов можно изменить только в интерфейсе, здесь только реализация.
@ Override — аннотация которая говорит что метод переопределен.
И соответственно у нас есть 3 класса самих фигур, которые наследуются от класса Figure. Класс Figure является родительским классом или классом-родителем, а классы Circle, Rectungle и Triangle — являются дочерними.
public class Triangle extends devcolibri.com.oop.inheritance.Figure — это значит, что класс Triangle наследует класс Figure.
super.setColor(colour); — super модификатор, позволяющий вызывать методы из класса родителя.
Теперь каждый класс перенял свойства класса Figure. Что собственно это нам дало?
Значительно уменьшило время разработки классов самих фигур, дало доступ к полям и методам родительского класса.
Наверное возник вопрос: чем же extends отличается от implements?
Extends дает нам намного гибче подход. Мы используем только те методы, что нам нужны, в любой момент мы можем изменить каркас и тело метода, или добавить совсем новый метод, который возможно будет использовать информацию от класса родителя, а implements все лишь формирует тело класса.
В дочерних классах мы можем спокойно добавлять новые интересующие нас методы. Например, мы хотим добавить в класс Triangle 2-а новых метода: flimHorizontal () и flipVertical ():
Теперь эти 2-а метода принадлежат сугубо классу Triangle. Этот подход используется когда базовый класс не может решить всех проблем.
Или можно использовать другой подход, изменить или переписать методы в дочерним классе:
Довольно интересный факт: в java запрещено множественное наследование, но любой из классов по умолчанию наследуется то класса Object. То есть при наследовании любого класса у нас получается множественное наследование)
Но не стоит забивать этим голову!
Шаг 4.
Полиморфизм.
В более общем смысле, концепцией полиморфизма является идея “один интерфейс, множество методов“.
Это означает, что можно создать общий интерфейс для группы близких по смыслу действий. Преимуществом полиморфизма является то, что он помогает снижать сложность программ, разрешая использование того же интерфейса для задания единого класса действий. Выбор же конкретного действия, в зависимости от ситуации, возлагается на компилятор.
Вам, как программисту, не нужно делать этот выбор самому. Нужно только помнить и использовать общий интерфейс.
Прежде всего, нужно сказать, что такое объявление корректно.
Наследники могут объявлять поля с любыми именами, даже совпадающими с родительскими. Объекты класса Child будут содержать сразу две переменных, а поскольку они могут отличаться не только значением, но и типом (ведь это два независимых поля), именно компилятор будет определять, какое из значений использовать.
Компилятор может опираться только на тип ссылки, с помощью которой происходит обращение к полю:
Обе ссылки указывают на один и тот же объект, но тип у них разный. Отсюда и результат. Объявление поля в классе-наследнике «скрыло» родительское поле.
Данное объявление так и называется – «скрывающим». Родительское поле продолжает существовать.
К нему можно обратиться явно:
Переменные b и c получат значения, родительского поля a. Хотя выражение с super более простое, оно не позволит обратиться на два уровня вверх по дереву наследования.
А ведь вполне возможно, что в родительском классе это поле также было скрывающим и в родителе родителя храниться ещё одно значение.
К нему можно обратиться явным приведением, как это делается для b.
Метод вызывается с помощью ссылки типа Child, но метод определен в классеParent и компилятор расценивает обращение к полю x в этом методе именно как к полю класса Parent. Результатом будет 0.
Рассмотрим случай переопределения методов:
Родительский метод полностью перекрыт.
В этом ключевая особенность полиморфизма – наследники могут изменить родительское поведение, даже если обращение к ним производиться по ссылке родительского типа.
Хотя старый метод снаружи недоступен, внутри класса-наследника к нему можно обратиться с помощью super.
Статические методы, подобно статическим полям принадлежат классу и появление наследников на них не сказывается. Статические методы не могут перекрывать обычные методы и наоборот.
Шаг 5.
Абстракция:
Как говорилось в начале статьи, нельзя игнорировать абстракцию, а значит и абстрактные классы и методы.
В контексте ООП абстракция — это обобщение данных и поведения для типа, находящегося выше текущего класса по иерархии.
Перемещая переменные или методы из подкласса в супер класс, вы обобщаете их. Это общие понятия, и они применимы в языке Java. Но язык добавляет также понятия абстрактных классов и абстрактных методов.
Абстрактный класс является классом, для которого нельзя создать экземпляр.
Например, вы можете создать класс Animal (животное). Нет смысла создавать экземпляр этого класса: на практике вам нужно будет создавать экземпляры конкретных классов, например, Dog (собака). Но все классы Animal имеют некоторые общие вещи, например, способность издавать звуки. То, что Animal может издавать звуки, еще ни о чем не говорит.
Издаваемый звук зависит от вида животного.
Как это смоделировать?
Определить общее поведение в абстрактном классе и заставить подклассы реализовывать конкретное поведение, зависящее от их типа.
В иерархии могут одновременно находиться как абстрактные, так и конкретные классы.
Использование абстракции:
Наш класс Person содержит некоторый метод поведения, и мы пока не знаем, что он нам необходим. Удалим его и заставим подклассы реализовывать это поведение полиморфным способом. Мы можем сделать это, определив методы Person как абстрактные. Тогда наши подклассы должны будут реализовывать эти методы.
Что мы сделали в приведенном выше коде?
Объявляя метод абстрактным, вы требуете от подклассов либо реализации этого метода, либо указания метода в этих подклассах абстрактным и передачи ответственности по реализации метода к следующим подклассам. Можно реализовать некоторые методы в абстрактном классе и заставить подклассы реализовывать остальные. Это зависит от вас. Просто объявите методы, которые не хотите реализовывать, как абстрактные и не предоставляйте тело метода. Если подкласс не реализует абстрактный метод супер класса, компилятор выдаст ошибку.