Параметры методов Java
Передавайте значения в методы Java через параметры и узнайте разницу между параметрами и аргументами.
Параметры — это входные данные, которые объявляет метод; аргументы — это значения, которые вы передаёте при вызове. Компилятор проверяет, что аргументы соответствуют параметрам по типу и позиции, а затем передаёт их методу как локальные переменные, доступные в теле метода.
В этой главе подробно рассматривается эта передача — синтаксис, типы, которые можно передавать, и правила, которые Java применяет для преобразования между ними.
Объявление параметров
Список параметров метода — это последовательность пар Тип имя, разделённых запятыми:
public static void greet(String name, int times) {
for (int i = 0; i < times; i++) {
System.out.println("Hello, " + name);
}
}Метод может объявлять ноль, один или несколько параметров. Каждый из них требует собственного типа — нет сокращения вроде int a, b (это int a и b, что не скомпилируется).
Вызов с аргументами
В месте вызова значения передаются в том же порядке, в котором объявлены параметры:
greet("Ada", 3); // name = "Ada", times = 3Компилятор проверяет два условия:
- Арность — количество аргументов совпадает с количеством параметров.
- Типы — тип каждого аргумента совместим с типом соответствующего параметра.
Если одна из проверок не пройдена, программа не скомпилируется. Если передать String там, где ожидается int, вы получите ошибку вида incompatible types: String cannot be converted to int.
Параметры как локальные переменные
Внутри метода каждый параметр ведёт себя как локальная переменная, инициализированная значением аргумента:
public static int doubleIt(int n) {
n = n * 2; // legal: n is just a local
return n;
}
int x = 5;
int result = doubleIt(x); // result is 10
System.out.println(x); // still 5Переприсваивание n внутри doubleIt не влияет на x в месте вызова. Каждый вызов получает свою собственную копию параметра. Именно это имеют в виду, когда говорят, что Java использует передачу «по значению» — каждый аргумент копируется в слот параметра. В следующих главах рассматриваются последствия этого, особенно для аргументов-объектов.
Неявное расширение типов
Java автоматически расширяет числовой тип меньшего размера до большего, чтобы соответствовать параметру:
public static double half(double x) {
return x / 2;
}
int n = 7;
double result = half(n); // n is widened from int to doubleРасширение допустимо, потому что при этом не теряется информация. Сужение не происходит неявно — чтобы передать double в параметр типа int, требуется явное приведение:
half(7.5); // fine: double argument, double parameter
double d = 3.7;
int i = (int) d; // explicit cast
half(i); // also fineТе же правила расширения применяются, что и при присваивании: byte → short → int → long → float → double и char → int.
Параметры-объекты
Можно передавать любой объект — String, массив, пользовательский класс — объявив параметр соответствующего ссылочного типа:
public static int firstLength(String[] words) {
if (words.length == 0) return 0;
return words[0].length();
}
String[] colors = {"red", "green", "blue"};
System.out.println(firstLength(colors)); // 3Аргумент также может быть null, и в этом случае параметр будет null, а любое обращение к полю или вызов метода на нём бросит NullPointerException. Методы, принимающие ссылки, обычно выполняют проверку заранее или документируют, что null недопустим.
Передача null
null совместим по присваиванию с любым ссылочным типом, поэтому его можно передавать в любой параметр-объект:
greet(null, 1);Если метод обращается к параметру (name.length(), name.charAt(0), …), это приводит к исключению. Защитный метод явно обрабатывает null, часто с помощью проверки в начале:
public static void greet(String name, int times) {
if (name == null) name = "stranger";
for (int i = 0; i < times; i++) {
System.out.println("Hello, " + name);
}
}Параметры с модификатором final
Параметр можно пометить как final, чтобы запретить его переприсваивание внутри метода:
public static int doubleIt(final int n) {
// n = n * 2; // ERROR: cannot assign a value to final variable n
return n * 2;
}Это не меняет того, что видит вызывающий код — только то, разрешено ли телу метода повторно использовать слот параметра. Многие руководства по стилю рекомендуют считать все параметры final даже без ключевого слова: просто вычисляйте новые значения, не изменяя параметр.
Порядок вычисления аргументов
Когда вы пишете f(a(), b(), c()), аргументы вычисляются слева направо — все до вызова f. Если a() бросает исключение, b() и c() не выполняются.
public static int log(String label, int value) {
System.out.println(label + " = " + value);
return value;
}
public static int sum(int a, int b, int c) {
return a + b + c;
}
sum(log("a", 1), log("b", 2), log("c", 3));
// prints:
// a = 1
// b = 2
// c = 3Этот детерминизм отличает Java от C и C++; в Java порядок фиксирован и предсказуем.
Рабочий пример
Что дальше
Теперь вы знаете, как данные попадают в метод. Иногда нужно два метода с одним именем, но разными входными данными — например, один принимает int, а другой String. Java позволяет написать оба сразу с помощью перегрузки методов.