Основой создания новых классов является задание полей данных и методов. Но если поля отражают структуру данных, связанных с объектом или классом, то методы задают поведение объектов, а также работу с полями данных объектов и классов.
Формат объявления функции следующий:
Модификаторы Тип Имя (список параметров){
Тело функции
}
Это формат “простой” функции, не содержащей операторов, возбуждающих исключительные ситуации. Про исключительные ситуации и формат объявления функции, которая может возбуждать исключительную ситуацию, речь пойдёт в одном из следующих параграфов.
Комбинация элементов декларации метода
Модификаторы Тип Имя (список параметров)
называется заголовком метода.
Модификаторы – это зарезервированные слова, задающие
- Правила доступа к методу (private, protected, public). Если модификатор не задан, действует доступ по умолчанию – так называемый пакетный.
- Принадлежность к методам класса (static). Если модификатор не задан, считается, что это метод объекта.
- Невозможность переопределения метода в потомках (final). Если модификатор не задан, считается, что это метод можно переопределять в классах-потомках.
- Способ реализации (native – заданный во внешней библиотеке DLL, написанной на другом языке программирования; abstract – абстрактный, не имеющий реализации). Если модификатор не задан, считается, что это обычный метод.
- Синхронизацию при работе с потоками (synchronized).
В качестве Типа следует указать тип результата, возвращаемого методом. В Java, как мы уже знаем, все методы являются функциями, возвращающими значение какого-либо типа. Если требуется метод, не возвращающий никакого значения (то есть процедура), он объявляется с типом void. Возврат значения осуществляется в теле функции с помощью зарезервированного слова return.
Для выхода без возврата значения требуется написать
return;
Для выхода с возвратом значения требуется написать
return выражение;
Выражение будет вычислено, после чего полученное значение возвратится как результат работы функции.
Оператор return осуществляет прерывание выполнения подпрограммы, поэтому его обычно используют в ветвях операторов if-else или switch-case в случаях, когда необходимо возвращать тот или иной результат в зависимости от различных условий. Если в подпрограмме-функции в какой-либо из ветвей не использовать оператор return, будет выдана ошибка компиляции с диагностикой “missing return statement” – “ошибочное высказывание с return”.
Список параметров – это объявление через запятую переменных, с помощью которых можно передавать значения и объекты в подпрограмму снаружи, “из внешнего мира”, и передавать объекты из подпрограмму наружу, “во внешний мир”.
Объявление параметров имеет вид
тип1 имя1, тип2 имя2,…, типN имяN
Если список параметров пуст, пишут круглые скобки без параметров.
Тело функции представляет последовательность операторов, реализующую необходимый алгоритм. Эта последовательность может быть пустой, в этом случае говорят о заглушке – то есть заготовке метода, имеющей только имя и список параметров, но с отсутствующей реализацией. Иногда в такой заглушке вместо “правильной” реализации временно пишут операторы служебного вывода в консольное окно или в файл.
Внутри тела функции в произвольном месте могут задаваться переменные. Они доступны только внутри данной подпрограммы и поэтому называются локальными. Переменные, заданные на уровне класса (поля данных класса или объекта), называются глобальными.
Данные (значения или объекты) можно передавать в подпрограмму либо через список параметров, либо через глобальные переменные.
Сначала рассмотрим передачу в подпрограмму через список параметров значений примитивного типа. Предположим, что мы написали в классе MyMath метод mult1 умножения двух чисел, каждое из которых перед умножением увеличивается на 1. Он может выглядеть так:
double mult1(double x, double y){
x++;
y++;
return x*y;
}
Вызов данного метода может выглядеть так:
double a,b,c;
…
MyMath obj1=new MyMath();//создали объект типа MyMath
…
c=obj1.mult1(a+0.5,b);
Параметры, указанные в заголовке функции при её декларации, называются формальными. А те параметры, которые подставляются во время вызова функции, называются фактическими. Формальные параметры нужны для того, чтобы указать последовательность действий с фактическими параметрами после того, как те будут переданы в подпрограмму во время вызова. Это ни что иное, как особый вид локальных переменных, которые используются для обмена данными с внешним миром.
В нашем случае x и y являются формальными параметрами, а выражения a+0.5 и b – фактическими параметрами. При вызове сначала проводится вычисление выражений, переданных в качестве фактического параметра, после чего получившийся результат копируется в локальную переменную, используемую в качестве формального параметра. То есть в локальную переменную x будет скопировано значение, получившееся в результате вычисления a+0.5, а в локальную переменную y – значение, хранящееся в переменной b. После чего с локальными переменными происходят все те действия, которые указаны в реализации метода. Соответствие фактических и формальных параметров идёт в порядке перечисления. То есть первый фактический параметр соответствует первому формальному, второй фактический – второму формальному, и так далее. Фактические параметры должны быть совместимы с формальными – при этом действуют все правила, относящиеся к совместимости примитивных типов по присваиванию, в том числе – к автоматическому преобразованию типов. Например, для mult1 можно вместо параметров типа double в качестве фактических использовать значения типа int или float. А если бы формальные параметры имели тип float, то использовать фактические параметры типа int было бы можно, а типа double – нельзя.
Влияет ли как-нибудь увеличение переменной y на 1, происходящее благодаря оператору y++, на значение, хранящееся в переменной b? Конечно, нет. Ведь действия происходят с локальной переменной y, в которую при начале вызова было скопировано значение из переменной b. С самой переменной b в результате вызова ничего не происходит.
А можно ли сделать так, чтобы подпрограмма изменяла значение в передаваемой в неё переменной? – Нет, нельзя. В Java значения примитивного типа наружу, к сожалению, передавать нельзя, в отличие от подавляющего большинства других языков программирования. Применяемый в Java способ передачи параметров называется передачей по значению.
Иногда бывает нужно передать в подпрограмму неизменяемую константу. Конечно, можно проверить, нет ли где-нибудь оператора, изменяющего соответствующую переменную. Но надёжней проверка на уровне синтаксических конструкций. В этих целях используют модификатор final. Предположим, что увеличивать на 1 надо только первый параметр, а второй должен оставаться неизменным. В этом случае наш метод выглядел бы так:
double mult1(double x, final double y){
x++;
return x*y;
}
А вот при компиляции такого кода будет выдано сообщение об ошибке:
double mult1(double x, final double y){
x++;
y++;
return x*y;
}