Java. Добавление поведения.

Методы доступа (accessor)

Просмотр содержимого нашего объекта Adult при помощи прямых ссылок на переменные был удобен, но обычно это не очень хорошо, когда другой объект может копаться во внутренностях другого подобным образом. Это нарушает принцип инкапсуляции, о котором мы говорили ранее, и позволяет одному объекту вмешиваться во внутреннее состояние другого объекта.

Более разумным подходом является предоставление возможности одному объекту рассказать другим объектам о значениях своих переменных экземпляра по запросу. Для этого используются методы доступа ( accessor ).

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

В Java-сообществе эти методы доступа обычно называются методами getter и setter, поскольку их названия начинаются с get и set . Они представляют собой простейшие методы, которые вы когда-либо увидите, поэтому они являются хорошими кандидатами для иллюстрации основных концепций методов. Вы должны знать, что методы доступа являются общим понятием для методов, которые получают информацию об объекте. Не все методы доступа следуют соглашениям по наименованию для методов getter и setter, что мы увидим далее.

Вот некоторые общие характеристики методов getter и setter:

  • Спецификатором доступа для методов getter и setter обычно является public .
  • Методы getter обычно не используют какие-либо параметры.
  • Методы setter обычно принимают параметры и часто только один, который является новым значением переменной экземпляра, которую они устанавливают.
  • Возвращаемый тип данных метода getter обычно такой же, что и тип переменной экземпляра, значение которой он возвращает.
  • Возвращаемый тип данных метода setter обычно равен void . Это означает, что они ничего не возвращают (они только устанавливают значение переменной экземпляра).

Объявление методов доступа

Мы можем добавить методы доступа для переменной экземпляра age объекта Adult следующим образом:

public int getAge() {
	return age;
}
public void setAge(int anAge) {
	age = anAge;
}

Метод getAge() возвращает значение переменной age при помощи ключевого слова return . В методах, которые не возвращают результат, последним оператором является return void; . В данном методе getter мы ссылаемся на age по ее имени.

Мы также могли использовать оператор return this.age; . Переменная this ссылается на текущий объект. Она подразумевается, когда вы ссылаетесь на переменную экземпляра напрямую. Некоторые ОО-программисты из мира Smalltalk предпочитают использовать this всегда, когда ссылаются на переменную экземпляра, точно так же, как они использовали ключевое слово self при кодировании в Smalltalk. Я и сам люблю так поступать, но в языке Java это не требуется (и при этом на экран добавляется дополнительная информация), поэтому в примерах данного руководства мы не будем использовать этот прием до тех пор, пока код без него станет менее понятным.

Вызов методов

Теперь, когда у нас есть методы доступа, мы должны заменить прямой доступ к переменной age в нашем методе main() на вызов метода. main() теперь должен выглядеть следующим образом:

public static void main(String[] args) {
	Adult myAdult = new Adult();
	System.out.println("Name: " + myAdult.name);
	System.out.println("Age: " + myAdult.getAge());
	System.out.println("Race: " + myAdult.race);
	System.out.println("Gender: " + myAdult.gender);
}

Если вы выполните этот код снова, результаты должны быть такими же, что и раньше. Обратите внимание на то, что вызвать метод объекта легко. Используйте следующую форму:

instanceName.methodName()

Если метод не принимает параметры (как наш метод getter), вы все равно должны добавить круглые скобки после имени вызываемого метода. Если метод принимает параметры (как наш метод setter), укажите их внутри круглых скобок, разделяя запятыми в том случае, если их больше одного.

Пару слов о методе setter перед продолжением работы: Он принимает параметр int с названием anAge . Затем присваивает значение этого параметра переменной экземпляра age . Мы могли бы назвать параметр как угодно. Имя не важно, но, используя этот параметр внутри метода, вы должны применять именно указанное вами имя.

Перед продолжением работы давайте попробуем использовать метод setter . Добавьте следующую строку в метод main() сразу после создания экземпляра Adult :

myAdult.setAge(35);

Теперь выполним код опять. Результат должен быть равен 35. Вот что происходило за кулисами:

  • Мы передали целочисленное значение в метод в качестве параметра.
  • JRE выделил оперативную память для параметра и назвал его anAge .

Методы, не являющиеся методами доступа

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

public String speak() {
	return "hello";
}

Пока синтаксис должен быть вам знаком. Метод возвращает строку символов. Давайте используем его и очистим метод main() . Измените первый вызов println() на:

System.out.println(myAdult.speak());

Повторите выполнение кода. Вы должны увидеть слово hello на консоли.

Строки

Мы использовали несколько переменных с типом String , но до сих пор их не рассмотрели. Обработка строк в языке C трудоемка, поскольку они являются массивами 8-битных символов, заканчивающимися нулевым символом, которыми вы должны были управлять. В языке Java строки — это первоклассные объекты типа String , имеющие методы, которые помогут вам их обрабатывать. Что касается строк из C-мира, то наиболее похожим Java-кодом является примитивный тип данных char , который хранит один символ в кодировке Unicode, например ‘a’ .

Вы уже видели, как создать экземпляр объекта String и установить его значение, но существуют и другие способы сделать это. Вот несколько способов создания экземпляра String со значением «hello»:

String greeting = "hello";
String greeting = new String("hello");

Поскольку строки в языке Java являются объектами, вы можете использовать оператор new для создания экземпляра. Установка переменной типа String приведет к этому же результату, поскольку Java создает объект String для хранения символов, затем присваивает этот объект переменной экземпляра.

Вы можете сделать многое с переменными String ; класс имеет большое число полезных методов. Даже не используя методы, мы уже делали кое-что интересное с переменными String путем соединения пары строк:

System.out.println("Name: " + myAdult.getName());

Вместо использования + мы могли бы вызвать метод concat() String для соединения ее с другой строкой:

System.out.println("Name: ".concat(myAdult.getName()));

Этот код может выглядеть немного странным, поэтому давайте рассмотрим его вкратце, слева направо:

  • System — это встроенный объект, который позволяет вам взаимодействовать с различными сущностями системной среды (в том числе и с некоторыми собственными возможностями Java-платформы).
  • out — это переменная класса в System . Это означает, что она доступна без создания экземпляра System . Она представляет консоль.
  • println() — это метод out , принимающий параметр String , отображающий его на консоли и завершающий отображение символом новой строки.
  • «Name: « — это строка символов. Java-платформа обрабатывает этот литерал как экземпляр String , поэтому мы можем вызывать его методы напрямую.
  • concat() — это метод экземпляра String , который принимает параметр String и соединяет его со строкой, чей метод вы вызвали.
  • myAdult это наш экземпляр Adult.
  • getName() — это метод доступа для name переменной экземпляра.

Итак, JRE берет имя нашего объекта Adult , вызывает в нем метод concat() и добавляет «Bob» к «Name: «.

В Eclipse вы можете увидеть все доступные методы любого объекта, поместив вашу точку вставки после точки, которая следует за переменной, содержащей экземпляр, и нажав затем Ctrl-Spacebar. При этом отобразится список методов объекта, находящегося слева от точки. Вы можете пролистать список (он свернут) при помощи стрелок управления курсором на вашей клавиатуре, выделить желаемый метод и нажать Enter для его выбора. Например, для просмотра всех методов, доступных для объектов String , поместите вашу точку вставки после точки, следующей после «Name: «, и нажмите Ctrl-Spacebar.

Использование строк

Теперь давайте используем соединение строк в нашем классе Adult . До сих пор мы имели переменную экземпляра name . Неплохо было бы иметь firstname и lastname , затем объединить их, когда кто-либо запрашивает у Adult его имя. Нет проблем! Добавьте следующий метод:

public String getName() {
	return firstname + " " + lastname;
}

Eclipse должен был показать красные волнистые линии в методе, поскольку эти переменные экземпляра еще не существуют. Это означает, что код не может быть откомпилирован. Теперь замените существующую переменную экземпляра name двумя следующими (со значениями по умолчанию они имеют больший смысл):

protected String firstname = "firstname";
protected String lastname = "lastname";

Затем замените первый вызов println() следующим вызовом:

System.out.println("Name: " + myAdult.getName());

Теперь у нас есть более симпатичный метод getter для наших переменных. Он соединяет их для создания полного имени Adult . Мы могли бы также записать getName() следующим образом:

public String getName() {
	return firstname.concat(" ").concat(lastname);
}

Этот код делает то же самое, но демонстрирует явное использование метода String и построение цепочки вызовов методов. Когда мы вызываем concat() для firstname со строкой символов (пробел), метод возвращает новый объект String , являющийся их комбинацией. Затем мы сразу же вызываем метод concat() этого нового объекта для соединения с lastname . В результате получаем красиво отформатированное полное имя.

Арифметические операторы и операторы присваивания

Наш объект Adult может говорить (метод speak), но не может двигаться (move). Давайте добавим поведение для «перемещения».

Прежде всего, добавим переменную экземпляра для отслеживания количества шагов, сделанных объектом Adult :

public int progress = 0;

Теперь добавим метод с названием walk() :

public String walk(int steps) {
	progress = progress + steps;
	return "Just took " + steps + " steps";
}

Наш метод принимает целочисленный параметр, указывающий количество шагов, которые нужно сделать, обновляет переменную progress, хранящую это количество шагов, и отображает на экране некоторые результаты. Также хорошо было бы добавить метод getter для переменной progress ; setter не нужен. Почему? Действительно, разрешать другому объекту телепортировать нас вперед на некоторое количество шагов, возможно, не такая хорошая идея. Если другой объект хочет указать нам переместиться, он может вызвать walk() . Это, безусловно, законный вызов, хотя наш пример и является тривиальным. В реальном проекте такие решения по дизайну приложения должны приниматься постоянно, и часто их нельзя предусмотреть, независимо от того, что говорят гуру объектно-ориентированного дизайна (ООД).

В нашем методе мы обновляем переменную progress , добавляя к ней значение steps . Мы опять сохраняем результат в progress . Мы использовали самый общий оператор присваивания = для сохранения результата. Арифметический оператор + мы применили для сложения значений. Существуют другие способы достичь этой же цели. Следующий код делает то же самое:

public String walk(int steps) {
	progress += steps;
	return "Just took " + steps + " steps";
}

Применение оператора присваивания += немного менее неуклюже, чем применение оператора = в нашем первом варианте. Это предохраняет нас от использования ссылки на переменную progress дважды. Но происходит то же самое: добавляется значение steps к переменной progress и результат сохраняется в progress .

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

Оператор Использование

Описание

+ a + b Добавляет a и b
+ +a Преобразовывает a к типу int , если эта переменная имела тип byte , short или char
a — b Вычитает b из a
-a Арифметическое отрицание a
* a * b Умножает a и b
/ a / b Делит a на b
% a % b Возвращает остаток от деления a на b

(другими словами, это оператор взятия по модулю)

++ a++ Увеличивает a на 1 ; использует для вычисления значение переменной a перед увеличением
++ ++a Увеличивает a на 1 ; использует для вычисления значение переменной a после увеличения
a— Уменьшает a на 1 ; использует для вычисления значение переменной a перед уменьшением
—a Уменьшает a на 1 ; использует для вычисления значение переменной a после уменьшения
+= a += b Аналогично a = a + b
-= a -= b Аналогично a = a — b
*= a *= b Аналогично a = a * b
%= a %= b Аналогично a = a % b

Мы также уже встречали и другие обозначения, которые называются операторами в языке Java. Например: . (точка), которая определяет названия пакетов и вызывает методы; ( params ) , который разделяет запятыми список параметров метода; new , который вместе с именем конструктора создает экземпляр объекта. В следующем разделе мы встретим несколько других операторов.

Рейтинг
( Пока оценок нет )
Загрузка ...