Java ооп наследование пример

Как работают принципы ООП в Java: примеры

Принципы и понятия объектно-ориентированного программирования (ООП, или OOPS, Object-Oriented Programming Concepts) очень важны. Не разбираясь в понятиях ООП, вы не сможете проектировать системы в модели объектно-ориентированного программирования.

Модель объектно-ориентированного программирования

Модель объектно-ориентированного программирования построена вокруг понятия объекта. Объект – это экземпляр класса. Он содержит свойства и функции. По сути они похожи на объекты реального мира: как, например, машина, дом, ноутбук и т. д. У них есть свои свойства и определенные методы для выполнения действий. Что такое класс? Класс определяет схему объектов. Он определяет свойства и функции объектов. К примеру, книга — это класс, а конкретно ваша книга — его экземпляр.

Принципы ООП

Основными принципами ООП являются:

  1. Абстракция
  2. Инкапсуляция
  3. Полиморфизм
  4. Наследование
  5. Ассоциация и агрегация
  6. Композиция

Теперь по порядку рассмотрим эти понятия объектно-ориентированного программирования. Чтобы вы лучше поняли, как реализовать концепции ООП, мы будем использовать фрагменты кода на языке программирования Java.

Абстракция

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

Инкапсуляция

Инкапсуляция — это метод, используемый для реализации абстракции в ООП. Она ограничивает доступ к членам и методам класса. Для инкапсуляции в ООП применяются ключи модификаторов доступа. Например, в языке java инкапсуляция достигается с помощью ключевых слов private, protected и public.

Полиморфизм

Полиморфизм указывает, что в разных ситуациях объект ведет себя по-разному. Существует два типа полиморфизма – полиморфизм во время компиляции и во время выполнения. Полиморфизм во время компиляции достигается перегрузкой метода.

Читайте также:  Javascript input value onkeyup

Для примера рассмотрим такой класс:

public class Circle public void draw() System.out.println("Drwaing circle with default color Black and diameter 1 cm."); > public void draw(int diameter) System.out.println("Drwaing circle with default color Black and diameter"+diameter+" cm."); > public void draw(int diameter, String color) System.out.println("Drwaing circle with color"+color+" and diameter"+diameter+" cm."); > >

Все методы draw, которые встречаются в этом коде, ведут себя по-разному. Это пример перегрузки метода, потому что имена методов одинаковы, а аргументы разные. Поскольку компилятор сможет определить метод вызова во время компиляции, данный метод называется полиморфизмом во время компиляции. Полиморфизм во времени выполнения реализуется, когда между объектами есть отношения наследования «IS-A». Также этот подход называется переопределением метода, поскольку подкласс должен переопределить метод суперкласса. Фактический класс определяется во время выполнения с точки зрения суперкласса. Компилятор не может решать, какой метод класса будет вызван. Это решение принимается во время выполнения, отсюда и название – «полиморфизм во время выполнения» или «динамическая диспетчеризация методов».

package com.journaldev.test; public interface Shape public void draw(); > package com.journaldev.test; public class Circle implements Shape @Override public void draw() System.out.println("Drwaing circle"); > > package com.journaldev.test; public class Square implements Shape @Override public void draw() System.out.println("Drawing Square"); > >

Тут Shape — это суперкласс, у которого есть два подкласса, Circle и Square. Ниже приведен пример полиморфизма во время выполнения.

Shape sh = new Circle(); sh.draw(); Shape sh1 = getShape(); //some third party logic to determine shape sh1.draw();

В этих примерах компилятор Java не знает фактического класса реализации Shape, который будет использоваться во время выполнения.

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

Наследование — это понятие объектно-ориентированного программирования, которое указывает, что один объект основан на другом объекте, вытекает из него. Проще говоря, наследование — это механизм повторного использования кода. Наследуемый объект называется суперклассом, а объект, который наследует суперкласс, называется подклассом. В java для реализации наследования используется ключевое слово extends. Давайте посмотрим на следующий пример наследования в java.

package com.journaldev.java.examples1; class SuperClassA public void foo() System.out.println("SuperClassA"); > > class SubClassB extends SuperClassA public void bar() System.out.println("SubClassB"); > > public class Test public static void main(String args[]) SubClassB a = new SubClassB(); a.foo(); a.bar(); > >

Ассоциация

Такое поняте ООП, как ассоциация, определяет связи между объектами, а также разнообразие самих объектов. Предположим, что у нас есть объекты “Учитель” и “Ученик”: множество учеников может общаться с одним учителем, и, конечно, один ученик также может общаться с несколькими учителями.

Агрегация

Агрегация – это особый тип ассоциации. Это понятие подразумевает, что все объекты имеют свой собственный жизненный цикл, но со взаимосвязью «HAS-A» – то есть один дочерний объект может принадлежать одному родительскому . Каждый раз, когда вы встречаете взаимосвязь «HAS-A» между объектами, знайте – это называется агрегацией.

Композиция

Композиция – специальная “ограничительная” форма агрегации. В композиции содержащийся в отношении «HAS-A» объект не может существовать сам по себе. Представим, например, комнату, которая находится в доме . Одна комната не может быть частью двух разных домов. Конечно, если вы удалите дом, комната тоже будет удалена.

Больше примеров кода вы найдете в нашем репозитории GitHub .

Источник

Java ооп наследование пример

Исходя из схемы выше, реализуем 4 класса: Pixel , Snake , Food , Bonus .

Иллюстрация проблемы множественного наследования

Получаем дилемму: если объект класса Enemy вызывает метод canBeEaten () , определенный в классе Pixel и при этом не переопределенный в классе Enemy , а классы Snake и Food определили этот метод каждый по-своему. Возникает вопрос: от какого класса должен наследовать свое поведение экземпляр класса Enemy : Snake или Food ? Такая конфигурация наследования называется «проблемой множественного наследования».

В Java для решения этой проблемы применяются интерфейсы.

Что такое интерфейс?

Интерфейс – это объект языка Java схожий по своей сути с абстрактным классом. Для определения интерфейса в языке есть отдельное ключевое слово interface.

Интерфейс не обязан иметь в себе сигнатуры методов. Пустые интерфейсы называются интерфейсами-маркерами. Классическим примером интерфейса-маркера можно считать Cloneable из пакета java.lang .

Отличия абстрактного класса от интерфейса

Если интерфейс так похож на абстрактный класс, зачем тогда в языке присутствуют обе эти конструкции? Для этого есть несколько причин:

  1. Идеологическая. В парадигме ООП все классы – существительные. Абстрактный класс не исключение. Следовательно, он описывает общие свойства объектов. Интерфейс же — это контракт. Он описывает общие действия доступные всем классам, реализующим его. Интерфейс не располагает реализацией – он лишь гарантирует наличие действия у объекта. Именно поэтому в некоторых нотациях принято именовать интерфейсы как Noun-able.
  2. Практическая. Класс может расширять только один класс и имплементировать множество интерфейсов. С помощью интерфейса можно решить проблему множественного наследования.

Пример интерфейса

Создадим интерфейс, определяющий возможность перемещаться, и имплементируем его:

Схема отношений классов без проблемы множественного наследования

Проведем рефакторинг в соответствии со схемой. Вынесем из абстрактного класса метод canBeEaten () в отдельный интерфейс и имплементируем его в абстрактном классе. Таким образом, мы реализовали контракт о том, что все классы дочерние от абстрактного обязаны у себя реализовать метод canBeEaten () что решает проблему выбора родителя для неопределенного метода и, как следствие, саму проблему ромба.

interface Eatable < boolean canBeEaten(); >abstract class Pixel implements Eatable < > 

Добавим также классу Snake интерфейс-маркер, чтобы отличать «живые» объекты. Например, змеек и, возможно, других персонажей от еды.

interface Alivable<> class Snake extends Pixel implements Movable, Alivable < > 

Таким образом, видно, что класс может расширять только один другой класс, но имплементировать множество интерфейсов.

​​Ссылки

Тема данной статьи достаточно обширна, и в ней остался не раскрыт ряд вопросов: применение интерфейсов маркеров или примесей, однако я надеюсь, что мне удалось осветить основные аспекты наследования в Java.

Подведем итог. В этой статье мы:

  1. Научились создавать интерфейсы, абстрактные классы и методы.
  2. Поняли, чем отличается абстрактный класс от интерфейса.
  3. Познакомились с проблемой множественного наследования, а также методами ее решения.

Материалы по теме

Источник

Оцените статью