Метод — это именованный блок кода, который выполняет определённую задачу. Представь метод как рецепт: у него есть название, список ингредиентов (параметры), и в конце он либо выдаёт готовое блюдо (возвращает значение), либо просто делает что-то (например, печатает текст).
Зачем использовать методы:
модификаторы тип_возврата имяМетода(параметры) {
// тело метода
return значение; // если тип_возврата не void
}Разберём по частям:
| Часть | Что означает | Пример |
|---|---|---|
| Модификаторы | Доступ и поведение | public, private, static |
| Тип возврата | Что метод возвращает | int, String, boolean, void |
| Имя | Название метода (camelCase) | calculateSum, isEven |
| Параметры | Входные данные | int a, int b |
| Тело | Код, который выполняется | { ... } |
public class MethodsDemo {
// 1. Метод без параметров, не возвращает ничего
public static void sayHello() {
System.out.println("Привет, Вика!");
}
// 2. Метод с параметрами, возвращает значение
public static int sum(int a, int b) {
return a + b;
}
// 3. Метод с условием, возвращает boolean
public static boolean isEven(int number) {
return number % 2 == 0;
}
// 4. Метод со строковым параметром и возвратом
public static String greet(String name) {
return "Привет, " + name + "!";
}
public static void main(String[] args) {
sayHello(); // "Привет, Вика!"
int result = sum(5, 3); // result = 8
System.out.println(isEven(4)); // true
System.out.println(greet("Аня")); // "Привет, Аня!"
}
}public static int absolute(int x) {
if (x < 0) {
return -x; // выходим сразу
}
return x; // сюда попадём, только если x >= 0
}
public static void printAndExit(int x) {
System.out.println(x);
return; // в void-методах return можно использовать для досрочного выхода
// System.out.println("не выполнится"); // 💥 недостижимый код
}| Модификатор | Кто может вызвать |
|---|---|
| public | Все из любого места |
| private | Только внутри своего класса |
| (без модификатора) | Только в своём пакете |
| protected | Свой пакет + наследники |
💡 Для обучения пока используй public static. Позже, когда изучишь ООП, разберёмся с private и нестатическими методами.
MyClass obj = new MyClass();
obj.myMethod();⚠️ Правило: из static метода нельзя напрямую обращаться к нестатическим методам и полям.
Метод вызывается по имени с указанием аргументов в скобках:
public class Calculator {
public static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
// Вызов с сохранением результата
int result = add(10, 20);
System.out.println(result); // 30
// Вызов сразу в выражении
System.out.println(add(5, 7) * 2); // 24
// Вызов как аргумент другого метода
System.out.println(add(add(1, 2), add(3, 4))); // 10
}
}Методы могут вызывать друг друга
public static int square(int x) {
return x * x;
}
public static int sumOfSquares(int a, int b) {
return square(a) + square(b); // вызываем square внутри
}
public static void main(String[] args) {
System.out.println(sumOfSquares(3, 4)); // 25 (9 + 16)
}Перегрузка — это возможность объявить несколько методов с одним именем, но разными параметрами. Компилятор сам поймёт, какой метод вызвать, по типу и количеству аргументов.
Пример
public class Printer {
public static void print(int value) {
System.out.println("Число: " + value);
}
public static void print(String text) {
System.out.println("Строка: " + text);
}
public static void print(int a, int b) {
System.out.println("Два числа: " + a + " и " + b);
}
public static void print(double value) {
System.out.println("Дробное: " + value);
}
public static void main(String[] args) {
print(42); // "Число: 42"
print("Привет"); // "Строка: Привет"
print(3, 7); // "Два числа: 3 и 7"
print(3.14); // "Дробное: 3.14"
}
}✅ Можно менять:
❌ Нельзя менять:
// ❌ ОШИБКА: отличается только возвращаемый тип
public static int getValue() { return 1; }
public static String getValue() { return "one"; } // компилятор не скомпилирует
// ✅ Правильно: разное количество параметров
public static int getValue() { return 1; }
public static String getValue(int x) { return "one"; }Вспомни System.out.println() — он перегружен десятки раз! Ты можешь передать int, String, double, boolean, объект — и всё работает.
System.out.println(42); // int
System.out.println("Привет"); // String
System.out.println(3.14); // double
System.out.println(true); // booleanЕсли точного совпадения нет, Java попробует привести тип:
public static void test(int x) { System.out.println("int"); }
public static void test(long x) { System.out.println("long"); }
public static void test(double x) { System.out.println("double"); }
test(42); // "int" — точное совпадение
test(42L); // "long" — точное совпадение
test(3.14); // "double" — точное совпадение
test((short)5); // "int" — short расширяется до intЭто очень важная тема, в которой часто путаются новички. В Java параметры всегда передаются по значению (pass-by-value), но есть нюанс для ссылочных типов.
public static void increment(int x) {
x = x + 1;
System.out.println("Внутри метода: " + x); // 6
}
public static void main(String[] args) {
int a = 5;
increment(a);
System.out.println("После вызова: " + a); // 5 — НЕ изменилось!
}Что произошло: 1. В main есть переменная a = 5 2. При вызове increment(a) создаётся копия значения 5 и кладётся в параметр x 3. x и a — две разные переменные в разных участках памяти 4. Изменение x внутри метода не влияет на a
А вот тут интересно. Передаётся копия ссылки на объект, а не сам объект.
public static void modifyArray(int[] arr) {
arr[0] = 999; // меняем содержимое объекта
}
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
modifyArray(numbers);
System.out.println(numbers[0]); // 999 — ИЗМЕНИЛОСЬ!
}Что произошло:
Но переназначить ссылку нельзя!
public static void reassign(int[] arr) {
arr = new int[]{10, 20, 30}; // создаём НОВЫЙ массив
arr[0] = 999;
}
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
reassign(numbers);
System.out.println(numbers[0]); // 1 — НЕ изменилось!
}Почему? Внутри метода arr — это копия ссылки. Когда мы написали arr = new int[]..., мы просто перенаправили копию на новый объект. Исходная numbers продолжает ссылаться на старый массив.
| Тип | Что передаётся | Можно изменить исходное? |
|---|---|---|
| Примитив (int, double и т.д.) | Копия значения | ❌ Нет |
| Ссылочный (String, массив, объект) | Копия ссылки | ✅ Содержимое — да, саму ссылку — нет |
Строки — ссылочный тип, но они неизменяемые (immutable). Поэтому изменить их содержимое нельзя:
Иногда нужно передать неизвестное количество аргументов одного типа. Для этого есть ...:
public static int sumAll(int... numbers) {
int sum = 0;
for (int n : numbers) {
sum += n;
}
return sum;
}
public static void main(String[] args) {
System.out.println(sumAll()); // 0
System.out.println(sumAll(1)); // 1
System.out.println(sumAll(1, 2, 3)); // 6
System.out.println(sumAll(1, 2, 3, 4, 5)); // 15
int[] arr = {10, 20, 30};
System.out.println(sumAll(arr)); // 60 — можно передать массив
}⚠️ Важно: varargs должен быть последним параметром:
public static void print(String prefix, int... numbers) // ✅
public static void print(int... numbers, String prefix) // ❌ ОШИБКАВнутри метода numbers ведёт себя как обычный массив int[].
Метод может вызывать сам себя. Это называется рекурсия.
public static int factorial(int n) {
if (n <= 1) {
return 1; // базовый случай (условие выхода)
}
return n * factorial(n - 1); // рекурсивный вызов
}
// factorial(5):
// 5 * factorial(4)
// 5 * 4 * factorial(3)
// 5 * 4 * 3 * factorial(2)
// 5 * 4 * 3 * 2 * factorial(1)
// 5 * 4 * 3 * 2 * 1 = 120StackOverflowError// ❌ ОПАСНО: бесконечная рекурсия
public static void bad(int n) {
bad(n); // никогда не остановится
}Переменные живут только внутри блока, где объявлены:
public static void example() {
int x = 10; // видна во всём методе
if (x > 5) {
int y = 20; // видна только внутри if
System.out.println(x); // ✅ OK
}
// System.out.println(y); // ❌ ОШИБКА: y не видна здесь
for (int i = 0; i < 3; i++) {
// i видна только внутри for
}
// System.out.println(i); // ❌ ОШИБКА
}💡 Правило: переменные живут минимально необходимый срок. Объявляй их как можно ближе к месту использования.
public static boolean isPrime(int n) {
if (n <= 1) return false;
if (n <= 3) return true;
if (n % 2 == 0) return false;
for (int i = 3; i <= Math.sqrt(n); i += 2) {
if (n % i == 0) return false;
}
return true;
}
public static void main(String[] args) {
for (int i = 1; i <= 20; i++) {
if (isPrime(i)) {
System.out.print(i + " ");
}
}
// 2 3 5 7 11 13 17 19
}public static String reverse(String s) {
StringBuilder sb = new StringBuilder();
for (int i = s.length() - 1; i >= 0; i--) {
sb.append(s.charAt(i));
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(reverse("Привет")); // "тевирП"
}public static int findIndex(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i; // нашли — возвращаем индекс
}
}
return -1; // не нашли — возвращаем -1
}
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40, 50};
System.out.println(findIndex(numbers, 30)); // 2
System.out.println(findIndex(numbers, 99)); // -1
}public static int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.print(fibonacci(i) + " ");
}
// 0 1 1 2 3 5 8 13 21 34
}Метод-калькулятор — напиши 4 метода: add, subtract, multiply, divide. Каждый принимает два double и возвращает результат. В divide обработай деление на ноль.
Перегрузка max — напиши 3 перегруженных метода max:
для двух int
для трёх int
для массива int[]
Метод-палиндром — напиши метод isPalindrome(String), который проверяет, читается ли строка одинаково в обоих направлениях (без учёта регистра и пробелов).
Подсчёт символов — напиши метод countChar(String text, char c), который считает, сколько раз символ c встречается в строке text.
Рекурсия: степень — напиши метод power(int base, int exp), который вычисляет base в степени exp через рекурсию (без использования Math.pow).
Массив и метод — напиши метод, который принимает массив чисел и возвращает новый массив, содержащий только чётные числа из исходного.
Еще один из популярных вопросов на собеседовании Java-разработчика. Local variable — это переменная, которая определена внутри метода и существует вплоть до того момента, пока выполняется этот метод. Как только выполнение закончится, локальная переменная перестанет существовать.
Вот программа, которая использует локальную переменную helloMessage в методе main():
public static void main(String[] args) {
String helloMessage;
helloMessage = "Hello, World!";
System.out.println(helloMessage);
}Instance Variable — переменная, которая определена внутри класса, и она существует вплоть до того момента, пока существует объект.
Пример — класс Bee, в котором есть две переменные nectarCapacity и maxNectarCapacity:
public class Bee {
/**
* Current nectar capacity
*/
private double nectarCapacity;
/**
* Maximal nectar that can take bee.
*/
private double maxNectarCapacity = 20.0;
...
}Модификаторы доступа — это инструмент, при помощи которого можно настроить доступ к классам, методам и переменным.
Бывают следующие модификаторы, упорядоченные в порядке повышения доступа:
Переопределение методов происходит, когда child хочет изменить поведение parent класса. Если нужно, чтоб выполнилось-таки то, что есть в методе parent, можно использовать в child конструкцию вида super.methodName(), что выполнит работу parent метода, а уже потом добавить логику.
Требования, которые нужно соблюдать:
Сигнатура метода — это набор из названия метода и аргументов, какие принимает метод.
Сигнатура метода является уникальным идентификатором для метода при перегрузке методов.
Перегрузка методов — это свойство полиморфизма, в котором при помощи изменения сигнатуры метода можно создать разные методы для одних действий:
Например, один и тот же add() из ArrayList может быть перегружен следующим образом и будет выполнять добавление разным способом, в зависимости от входящих аргументов:
add(Object o) — просто добавляет объект;add(int index, Object o) — добавляет объект в определенный индекс;add(Collection<Object> c) — добавляет список объектов;add(int index, Collection<Object> c) — добавляет список объектов, начиная с определенного индекса.