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

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

Рассмотрим пример, в котором класс окружностей создаётся с использованием класса точек (одним из полей класса окружностей является объект-точка):

 

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

Полиморфизм

Примечательно также и то, что в классах у нас есть методы с одинаковыми именами. Например, методы print(), set(…), length().

Метод set имеет разные сигнатуры: в первом классе он получает два вещественных числовых аргумента, а во втором классе окружностей существует две реализации этого метода, у первой три вещественных числовых аргумента, а второй аргумента два, но первый это объект-точка, а второй — вещественное число. Соответсвенно, в момент вызова метода set никаких сложностей с тем, чтобы определить из какого класса должен исполняться метод — не возникнет (в силу разных наборов параметров).

А вот методы print() и length() вообще не имеют аргументов. И когда мы будем вызывать их в приложении к какому-то объекту, например, так:

 

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

Явление, когда разный программный код связан с одним и тем же именем (в данном примере с именем метода print()) называется — полиморфизмом (одно имя, но много форм).

Полиморфизм позволяет упростить использование создаваемых классов: пользователь любого из двух созданных нами классов будет знать, что для вывода описания объекта на экран надо использовать метод print(), не нужно даже задумываться какой именно это объект (т.е. к какому классу он относится).

С полиморфизмом вы уже сталкивались на примере перегрузки методов, в ООП контекстом для вызова конкретной реализации метода является уже не только набор аргументов, но и класс того объекта, к которому метод применяется.

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

Представленный выше пример содержит проблемный момент, связанный с тем, что ограничения на допустимые значения полей объектов никак не будут учитываться пользователем класса окружностей (внешней частью программы, где создаются и используются объекты класса). По смыслу моделируемой задачи поле r не должно получать отрицательных значений (ведь это радиус окружности). Мы учли это, например, в конструкторе, но пользователь класса может выполнять примерно такие действие, недопустимые с точки зрения предметной области задачи:

 

Для ограничения подобных действий, а также для сокрытия внутреннего устройства классов от пользователя (в целях безопасности и обеспечения модульнусти) существуют различные уровни доступа к членам класса (определяемые с помощью модификатора, пока нам хорошо знаком только модификатор public):

Модификаторы и зоны доступа Тело класса Пакет, содержащий класс Класс-наследник (подкласс) Вся остальная часть программы (например, другие пакеты)
public + + + +
protected + + +
default (модификатор не пишется) + +
private +

Из таблицы следует, что модификатор public предоставляет к полю или методу доступ из любой части программы. Это самый открытый и общедоступный вариант.

Напротив, модификатор private разрешает обращаться напрямую к члену класса только из самого класса. Это самый закрытый вариант.

Соответсвенно, изменив модификатор перед полем r класса окружностей мы можем решить описанную выше проблему:

 

Теперь попытка обратиться к свойству r из за пределов класса:

 

Будет приводить к ошибке:

 

Но что, если нам всё-таки потребуется обратиться к этому полю, чтобы изменить или прочитать его значения? Для этого можно добавить в класс методы, которые будут отвечать за изменение или чтение поля r, но при этом иметь более широкий уровень доступа (например, public):

 

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

Соответственно, теперь можно смело выполнять такой код (ошибки в программе не будет):

 

Методы, подобные созданным, назваются «геттеры» (от слова get, получать) и «cеттеры» (от слова set, устанавливать). Они являются обёртками для доступа к полям на чтение и запись, соответвенно.

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

Задачи

  1. Создайте класс треуголников на координатной плоскости, используя в качестве полей объекты-точки. Реализуйте в классе:
    a) конструктор, позволяющий задавать вершины с клавиатуры;
    b) метод print() выводящий описание треугольника на экран;
    c) методы для вычисления периметра и площади треугольника.
  2. Доработайте конструктор таким образом, чтобы нельзя было задать три вершины, лежащие на одной прямой. Это несложно будет сделать с использованием метода из класса точек, который проверяет явлются ли точки коллинеарными, если прежде вы не реализовали этот метод, то сейчас самое время сделать это.
  3. Инкапсулируйте поля таким образом, чтобы нельзя изменить значение любого из них так, чтобы вершины оказались на одной прямой.
  4. Создайте метод, поворачивающий треугольник вокруг центра тяжести на указанное в аргументе количество градусов.

< Предыдущая       Оглавление       Следующая >

Создание собственных классов в Java (продолжение), инкапсуляция, полиморфизм, модификаторы доступа обновлено: Ноябрь 24, 2015 автором: admin

  1. Нет ли здесь ошибки?

    // метод перемещает центр окружности на указанный вектор
    public void move(double a, double b) {
    c.move(a, b);
    }

    По-моему, должно быть c.movePoint(a,b);

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*
*
Website