Учебная страница курса биоинформатики,
год поступления 2010
Title
Интерфейсы
В прошлый раз мы выяснили как работает наследование. Основная его функция — перенесение общих для некоторых объектов функций в надкласс во избежание дублирования кода. Часто бывает другая ситуация: разные объекты должны делать разные вещи в одной и той же ситуации. Например разные компьютеры (программы) могут совершенно по разному реагировать на нажатие одних и тех же клавиш на клавиатуре. Или у всех живых существ, имеющих ноги, есть реакция на то что вы им ее отдавите, но реакция разная: взбалмашная дама влепит вам пощечину, собака укусит, а ребенок заплачет.
Подобная ситуация часто бывает и в программировании, когда вам надо обращаться с разными в принципе объектами единообразно. В приведенных выше примерах клавиатура компьютера, нога животного выступали интерфейсом через который мы взаимодействовали с объектом — компьютером или животным. В Java для этой цели тоже есть интерфейсы.
Вернемся к нашему примеру про офис: обычно начальник с некоторой регулярностью проводит среди сотрудников внушения с целью увеличения их трудоспособности. В этом деле ему абсолютно все равно, что это за сотрудник (и даже сотрудник ли — можно увеличить работоспособность (производительность) техники — например принтера) перед ним. Поэтому заведем соответствующий интерфейс:
А у боса метод для улучшения техники и сотрудников:
Осталось только понять как сделать чтобы например секретарша была «улучшаема», т.е. реализовывала интерфейс Refinable. Это делается так:
А чтобы все это работало в нашем коде напишем следующие в OfficeLife:
Здесь возникает один вопрос: переменная secretary имеет тип Secretary, однако мы передаем ее методу refineEmployee которые требует в качестве параметров тип Refinable. На самом деле в Java можно передавать в качестве параметра любые классы реализующие интерфейс указанный в качестве типа параметра.
Что такое в результате интнерфейс — это почти что класс, только в нем не написано что именно делают его методы. А классы реализующие данный интерфейс определяют все его методы.
Инкапсуляция. Модификаторы доступа
Инкапсуляция — это принцип, согласно которому любой класс должен рассматриваться как чёрный ящик — пользователь класса должен видеть и использовать только интерфейсную часть класса (т. е. список декларируемых свойств и методов класса) и не вникать в его внутреннюю реализацию. Все, что необходимо знать пользователю (программисту) про работу того или иного метода описывается в его документации. Для осуществления принципа инкапсуляции в Java используются модификаторы доступа, которые определяют правила доступа к переменным и методам классов.
Есть четыре уровня доступа к свойствам и методам класса:
public
private
protected (дает доступ наследникам класса; понятно, что наследникам может потребоваться доступ к некоторым элементам родителя, с которыми не приходится иметь дело внешним классам.)
<empty> (если модификатор не указан)
Области видимости полей и методов с разными модификаторами доступа:
Слово |
Из того же пакета |
Из другого пакета |
Из наследника |
public |
+ |
+ |
+ |
protected |
+ |
- |
+ |
private |
- |
- |
- |
<empty> |
+ |
- |
- |
Правила доступа имеют важный смысл, связанный с тем, что классы в проекте располагаются по пакетам. Внутри одно пакета часто находятся классы, отвечающие за связанные между собой действия, и как это часто бывает, разработаны одним человеком или небольшой группой разработчиков. И если разработчик какого-нибудь класса хочет ограничить возможность того, что пользователи этого класса будут вмешиваться в работу объектов этого класса, то ему приходят на выручку эти модификаторы.
Давайте опять вернемся к нашему примеру про офис. Ясно, что в примере про класс Secretary мы не хотели бы давать возможность пользователю этого класса задать отрицательную длину ногтей или пустое имя. Для этого мы ограничим доступ к полям name и nails_length модификатором private. Но для того, чтобы иметь возможность менять и узнавать значения этих свойств, нам придется сделать по два публичных метода для каждого из свойств: один метод меняет значение, другой – его возвращает. Обычно их называют как set… и get… (например, getName()), т.е. "сеттеры" и "геттеры". И в сеттере мы можем уже отслеживать, на какое значение пользователь хочет изменить длину ногтей. А для имени в данном случае мы вообще не будем делать сеттер — потому что имя задается при создании объекта и менять его после этого незачем.
На всякий случай хочется уточнить, что значит «пользователь хочет изменить»? Конечно, пользователь в данном случае — это программист, который пользуется данным ему классом (или классом, который он сам же и написал). Например, мы или кто-то написал класс Secretary, и теперь мы пишем какой-то другой класс, использующий класс Secretary. И если программист, написавший класс Secretary не скрыл с помощью модификаторов поля имени и длины ногтей, то мы сможем менять их как захотим, что может привести к ошибкам.
Модификатор static
Бывает так, что в классе нужно создать переменную, нужную классу в целом, а не каждому объекту класса. Например, нужно знать, сколько объектов данного класса создано в данный момент. Или надо хранить значение, одинаковое для всех объектов класса – константу (максимальная длина ногтей у секретарши). В этом случае используется модификатор static. Переменная, объявленная как static, не зависит от конкретного объекта. Ключевое слово static привязывает свойства и методы к классу, а не к объекту. Обращение к ней происходит через имя класса. Например:
Теперь в программе мы можем узнать, сколько объектов типа Secretary у нас уже создано в программе:
1 System.out.println("number of secretaries = " + Secretay.getSecretaryCount ());
Метод getSecretaryCountв нашем примере тоже статический. Такие методы не зависят от конкретных объектов класса, поэтому, не могут обращаться к их переменным. Они могут обращаться только к статическим переменным класса и работать с данными, которые даются им на вход. Вызов метода также происходит не у объекта, а у класса.
Нестатические поля недоступны в статических методах.
Ключевое слово final
Ключевое слово final означает:
свойство, значение которого нельзя менять (поля с модификатором final должны инициализироваться при объявлении). Это часто используется для создания констант. (например, макс длина ногтей секретарш)
- метод, который нельзя переписать
- класс, который нельзя расширить