Выполнение метода и возврат из него
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

При вызове метода управление передаётся из того места кода, откуда был осуществлён вызов, в тело метода. Выражения тела метода выполняются в порядке, предусмотренном его семантикой. Метод завершает работу и передаёт управление обратно в код-инициатор в результате возникновения одного из трёх возможных событий: выполнение команды return, достижения конца тела метода (только для методов, «возвращающих» void) или генерации исключения. Если метод предусматривает возврат какого-либо значения, им может быть только одно значение простого или объектного типа. Методы, которые по смыслу должны возвращать несколько значений, способны решить эту задачу одним из следующих способов:

1. возвратить ссылку на объект, который содержит поля с требуемыми значениями;

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

3. возвратить массив объектов нужного типа.

4. разместить результат в public-полях этого же объекта.

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

Пример 11.

public class Permissions {

public boolean canDeposit, // Приход

                          canWithdraw, // Расход

                          canClose;  // Закрытие счёта

}

А вот так может выглядеть метод, предусматривающий заполнение полей объекта типа Permissions и возврат его:

public class BankAccount {

private long number; // Номер счёта

private long balance; // Остаток на счёте

public Permissions permissionsFor(Person who) {

       Permissions perm = new Permissions();

       perm.canDeposit = canDeposit(who);

      perm.canWithdraw = canWithdraw(who);

      perm.canClose = canClose(who);

     return perm ;

}

   // Объявление методов canDeposit и т.д…

}

Любой вызов метода, предусматривающего возврат некоторого значения, должен завершаться либо выполнением соответствующей команды return, передающей в код-инициатор значение, которое может быть присвоено переменной соответствующего типа, либо выбрасыванием объекта исключения. Методом permissionsFor не должен возвращаться, например, объект класса String , поскольку тот не удастся присвоить переменной типа Permissions (в таких ситуациях говорят о несовместимости типов). Но ничто не запрещает объявить в качестве наименования типа, возвращаемого методом permissionsFor , класс Object , совершенно не затрагивая выражения return , так как ссылка на объект Permissions может быть присвоена переменной типа Object (если вспомнить, что класс Object является базовым по отношению ко всем остальным классам Java ).

Параметры метода

При вызове метода аргументы передаются «по значению». Другими словами, значения переменных-параметров в теле метода – это копии тех значений, которые код-инициатор передал методу в виде аргументов. Если, например, метод получает в качестве аргументов значение типа double, в теле метода соответствующий параметр сохраняет копию значения, и возможные изменения этой копии в процессе работы метода никоим образом не воздействуют на содержимое переменных в коде-инициаторе. Рассмотрим следующий пример:

Пример 12.

class PassByValue { // Передача аргумента по значению

public static void main ( String [] args ) {

      double one = 1.0;

      System.out.println(“ до : one = ” + one);

      halveIt(one);

     System.out.println(“ после : one = ” + one);

}

 public static void halveIt(double arg) {

    arg /= 2.0; // Разделить значение arg пополам

   System.out.println(“ половина : arg = ” + arg);

}

}

Ниже показан результат работы программы – операция деления значения параметра arg в методе halveIt не влияет на содержимое переменной one в теле метода main .

до: one = 1.0

половина: arg = 0.5

после: one = 1.0

Следует заметить, что если аргумент представляет собой ссылку на объект, то «по значению» передаётся именно ссылка, но не объект как таковой. Таким образом, внутри тела метода можно присвоить ссылке другой объект, не воздействуя на содержимое исходной ссылки. Но если, пользуясь переданной ссылкой, попробовать изменить значение поля объекта, на который она указывает, или вызвать какой-либо из методов, изменяющих состояние объекта, тот действительно изменит своё состояние с точки зрения любого блока программы, в котором имеются ранее созданные ссылки на объект. Чтобы продемонстрировать названные нюансы, приведём пример:

Пример 13.

class PassRef { // Передача аргумента-ссылки

public static void main (String[] args) {

      Body venus = new Body (“ Венера ”, null);

      System.out.println(“ до : ” + venus);

      commonName(venus);

     System.out.println(“ после : ” + venus);

}

 public static void commonName (Body bodyRef) {

    bodyRef.name = “ Утренняя звезда ”;

    bodyRef = null;

}

}

Результат работы программы выглядит так:

до: 0 (Венера)

после: 0 (Утренняя звезда)

Обратите внимание, что состояние «внешнего» по отношению к методу commonName объекта поддалось изменению «изнутри» этого метода; кроме того, переменная venus всё ещё сохранила ссылку на тот же объект класса Body, а в методе commonName копия bodyRef ссылочной переменной venus получила другое значение null .

Следующий рисунок иллюстрирует состояние переменных непосредственно после вызова из main метода commonName .

Рисунок 2

В этот момент две переменные, venus в main и bodyRef в commonName , указывают на один и тот же объект. Когда метод commonName вносит изменения в поле bodyRef . name , модифицируется содержимое того же объекта, общего для двух ссылочных переменных. Когда же commonName присваивает переменной bodyRef значение null , изменяется значение только самой переменной bodyRef ; состояние ссылки venus остаётся прежним, поскольку параметр bodyRef – это копия переменной venus , переданная в качестве аргумента по значению. Единственный элемент данных, который в последнем случае подвергается воздействию – это параметр bodyRef как таковой (то же наблюдалось и в предыдущем примере, когда единственной «пострадавшей» стороной в процессе работы метода halveIt оказался параметр arg ). Если бы изменение bodyRef влияло на значение venus в main , строка после:, выводимая на экран, содержала бы слово null .

Существует ещё одно средство языка, имеющее прямое отношение к обсуждаемой теме: в объявлении метода параметры позволено помечать модификатором final, имея в виду, что значение параметра не может быть изменено в ходе выполнения тела метода. Будь bodyRef объявлен как final, компилятор не позволил бы изменить его значение на null. Если логика программы обусловливает недопустимость изменения значения параметра, достаточно снабдить его признаком final.

Дата: 2019-02-19, просмотров: 208.