Привет! Ты уже освоил создание собственных классов, с полями и методами. Сегодня мы как раз подробно поговорим про методы.
Мы, конечно, уже не раз делали это в наших лекциях, но мы говорили в основном об общих моментах. Сегодня же мы буквально разберем методы “по частям” — узнаем из чего они состоят, какие варианты их создания существуют и как всем этим можно управлять:) Поехали! ![Сигнатура метода - 1]()

Сигнатура метода
Весь код, который описывает метод, называется объявлением метода. Сигнатура метода включает название метода и типы параметров в определенном порядке. Общий вид объявления можно описать так:
модификатор доступа, тип возвращаемого значения, имя метода(список параметров) {
// тело метода
}
Рассмотрим для примера объявлений нескольких методов класса Dog
.
public class Dog {
String name;
public Dog(String name) {
this.name = name;
}
public static void main(String[] args) {
Dog max = new Dog("Макс");
max.woof();
}
public void woof() {
System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}
public void run(int meters) {
System.out.println("Собака по имени " + name + " пробежала " + meters + " метров!");
}
public String getName() {
return name;
}
}
1. Модификатор доступа
Модификатор доступа всегда указывается первым. Все методы классаDog
обозначены модификатором public
. То есть мы можем вызвать их из любого другого класса:
public class Main {
public static void main(String[] args) {
Dog butch = new Dog("Бутч");
butch.run(100);
}
}
Методы класса Dog
, как видишь, легко доступны в классе Main
.
Это возможно именно благодаря модификатору public
.
В Java есть и другие модификаторы, и не все из них позволят использовать метод внутри другого класса. О них мы поговорим в других лекциях.
Главное, запомни за что отвечает модификатор: за доступность/недоступность метода в других классах:)
2. Ключевое слово static
Один из методовDog
, а именно main()
обозначен ключевым словом static
.
Если же оно есть — то указать его необходимо после модификатора доступа.
Помнишь, в прошлых лекциях мы говорили о статических переменных класса?
Применительно к методам это слово имеет примерно тот же смысл.
Если метод указан как static
— это означает, что он может использоваться без ссылки на конкретный объект класса.
И действительно — чтобы запустить статический метод main()
в классе Dog
тебе не нужно создавать экземпляр Dog
, он запускается и без этого.
Если бы этот метод не был статическим — то для его использования нам понадобилось бы сперва создать объект.
3. Возвращаемое значение.
Если наш метод должен что-то вернуть, то далее мы указываем тип возвращаемого значения. Это видно на примере геттераgetName()
:
public String getName() {
return name;
}
Он возвращает объект типа String
.
Если же метод ничего не возвращает — вместо типа указывается ключевое слово void
, как в методе woof()
:
public void woof() {
System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}
Методы с одинаковыми именами
Бывают ситуации, когда в нашей программе нужно несколько вариантов работы метода. Почему бы нам не создать свой собственный искусственный интеллект? У Amazon есть Alexa, у Яндекса — Алиса, так чем мы хуже?:) В фильме про Железного Человека Тони Старк создал собственный выдающийся искусственный интеллект — J.A.R.V.I.S. Отдадим должное прекрасному персонажу и назовем наш ИИ в его честь:) Первое, чему мы должны научить Джарвиса — здороваться с людьми, которые заходят в комнату (будет странно, если столь великий интеллект окажется невежливым).
public class Jarvis {
public void sayHi(String name) {
System.out.println("Добрый вечер, " + name + ", как ваши дела?");
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Тони Старк");
}
}
Вывод в консоль:
Добрый вечер, Тони Старк, как ваши дела?
Отлично! Джарвис умеет приветствовать вошедшего. Чаще всего, конечно, это будет его хозяин — Тони Старк.
Но ведь он может прийти не один! А наш метод sayHi()
принимает на вход только один аргумент. И, соответственно, сможет поприветствовать только одного из пришедших, а другого проигнорирует. Не очень-то вежливо, согласен?:/
В этом случае чтобы решить проблему мы можем просто написать в классе 2 метода с одинаковым названием, но с разными параметрами:
public class Jarvis {
public void sayHi(String firstGuest) {
System.out.println("Добрый вечер, " + firstGuest + ", как ваши дела?");
}
public void sayHi(String firstGuest, String secondGuest) {
System.out.println("Добрый вечер, " + firstGuest + ", " + secondGuest + ", как ваши дела?");
}
}
Это называется перегрузкой методов. Перегрузка позволяет нашей программе быть более гибкой и учитывать различные варианты работы. Проверим как это работает:
public class Jarvis {
public void sayHi(String firstGuest) {
System.out.println("Добрый вечер, " + firstGuest + ", как ваши дела?");
}
public void sayHi(String firstGuest, String secondGuest) {
System.out.println("Добрый вечер, " + firstGuest + ", " + secondGuest + ", как ваши дела?");
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Тони Старк");
jarvis.sayHi("Тони Старк", "Капитан Америка");
}
}
Вывод в консоль:
Добрый вечер, Тони Старк, как ваши дела?
Добрый вечер, Тони Старк, Капитан Америка, как ваши дела?
Отлично, оба варианта сработали:)
Тем не менее, проблему мы не решили!
Что, если гостей будет трое? Конечно, мы можем еще раз перегрузить метод sayHi()
, чтобы он принимал имена трех гостей. Но их ведь может быть и 4, и 5. И так до бесконечности.
Нет ли другого способа научить Джарвиса работать с любым количеством имен, без миллиона перегрузок метода sayHi()
? :/
Конечно, есть! Иначе была бы разве Java самым популярным в мире языком программирования? ;)
public class Jarvis {
public void sayHi(String...names) {
for (String name: names) {
System.out.println("Добрый вечер, " + name + ", как ваши дела?");
}
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Тони Старк");
System.out.println();
jarvis.sayHi("Тони Старк", "Капитан Америка");
}
}
Запись (String...names
) переданная в качестве параметра позволяет нам указать, что в метод передается какое-то количество строк. Мы не оговариваем заранее сколько их должно быть, поэтому работа нашего метода становится теперь намного более гибкой:
public class Jarvis {
public void sayHi(String...names) {
for (String name: names) {
System.out.println("Добрый вечер, " + name + ", как ваши дела?");
}
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Тони Старк", "Капитан Америка", "Черная Вдова", "Халк");
}
}
Вывод в консоль:
Добрый вечер, Тони Старк, как ваши дела?
Добрый вечер, Капитан Америка, как ваши дела?
Добрый вечер, Черная Вдова, как ваши дела?
Добрый вечер, Халк, как ваши дела?
Внутри метода мы в цикле перебираем все аргументы и выводим готовые фразы с именами на консоль.
Здесь мы применяем упрощенный цикл for-each
(ты уже с ним сталкивался). Он отлично подходит, потому что запись String...names
— на самом деле означает, что все переданные параметры помещаются компилятором в массив. Поэтому с переменной names
можно работать как с массивом, в том числе — перебирать в цикле.
При этом он сработает при любом количестве переданных строк! Две, десять, хоть тысяча — метод будет стабильно работать с любым количеством гостей. Намного удобнее, чем делать перегрузки для всех возможных вариантов, согласен?:)
Приведем еще один пример перегрузки метода.
Добавим Джарвису метод printInfoFromDatabase()
. Он будет печатать в консоль информацию о человеке из базы данных. Если в базе данных указано, что человек является супергероем или суперзлодеем — эта информация также будет выведена на экран:
public class Jarvis {
public void printInfoFromDatabase (String bio) {
System.out.println(bio);
}
public void printInfoFromDatabase(String bio, boolean isEvil, String nickname) {
System.out.println(bio);
if (!isEvil) {
System.out.println("Также известен как супергерой " + nickname);
} else {
System.out.println("Также известен как суперзлодей " + nickname);
}
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.printInfoFromDatabase("Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Вашингтон");
System.out.println();
jarvis.printInfoFromDatabase("Макс Эйзенхарт. Рост 188см, вес 86 кг.", true, "Магнето");
}
}
Вывод:
Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Вашингтон
Макс Эйзенхарт. Рост 188см, вес 86 кг
Также известен как суперзлодей Магнето
Вот так, наш метод работает в зависимости от данных которые мы в него передаем.
Еще один важный момент: порядок следования аргументов имеет значение!
Допустим, наш метод принимает на вход строку и число:
public class Man {
public static void sayYourAge(String greeting, int age) {
System.out.println(greeting + " " + age);
}
public static void main(String[] args) {
sayYourAge("Мой возраст - ", 33);
sayYourAge(33, "Мой возраст - "); //ошибка!
}
}
Если метод sayYourAge()
класса Man
принимает на вход строку и число — значит именно в таком порядке их нужно передавать в программе! Если мы передадим их в другом порядке — компилятор выдаст ошибку и человек не сможет назвать свой возраст.
Кстати, конструкторы, которые мы проходили в прошлой лекции, тоже являются методами! Их тоже можно перегружать (создавать несколько конструкторов с разным набором аргументов) и для них тоже принципиально важен порядок передачи аргументов. Настоящие методы!:)
Как вызывать методы с похожими параметрами
Как ты знаешь, в Java есть такое слово как null. При работе с ним очень важно понимать, что null не является ни объектом, ни типом данных. Представь себе, что у нас есть класс Man и методintroduce()
, который объявляет имя человека и его возраст. При этом возраст можно передать в форме текста, а можно - числом.
public class Man {
public void introduce(String name, String age) {
System.out.println("Меня зовут " + name + ", мой возраст - " + age);
}
public void introduce(String name, Integer age) {
System.out.println("Меня зовут " + name + ", мой возраст - " + age);
}
public static void main(String[] args) {
Man sasha = new Man();
sasha.introduce("Саша", "двадцать один");
Man masha = new Man();
masha.introduce("Мария", 32);
}
}
С перегрузкой мы уже знакомы, поэтому знаем, что метод оба раза отработает как надо:
Меня зовут Саша, мой возраст - двадцать один
Меня зовут Мария, мой возраст - 32
Но что будет, если в качестве второго параметра мы передаем не строку и не число, а null?
public static void main(String[] args) {
Man victor = new Man();
victor.introduce("Виктор", null);//Ambiguous method call!
}
Мы получим ошибку компиляции!
Ошибка “Ambiguous method call” переводится как “двусмысленный вызов метода”.
Из-за чего она могла возникнуть и в чем заключается “двусмысленность”?
На самом деле все просто.
Дело в том, у нас есть два варианта метода: со String
и с Integer
в качестве второго аргумента.
Но и String
, и Integer
могут быть null!
Для обоих типов (поскольку они ссылочные) null является значением по умолчанию.
Именно поэтому компилятор в данной ситуации не может разобраться, какой вариант метода он должен вызвать.
Решить эту проблему достаточно просто. Дело в том, что null можно явно преобразовать к конкретному ссылочному типу.
Поэтому при вызове метода ты можешь указать в скобках нужный тебе тип данных для второго аргумента! Компилятор поймет твой “намек” и вызовет нужный метод:
public class Man {
public void introduce(String name, String age) {
System.out.println("Метод с двумя строками!");
System.out.println("Меня зовут " + name + ", мой возраст - " + age);
}
public void introduce(String name, Integer age) {
System.out.println("Метод со строкой и числом!");
System.out.println("Меня зовут " + name + ", мой возраст - " + age);
}
public static void main(String[] args) {
Man victor = new Man();
victor.introduce("Виктор", (String) null);
}
}
Вывод:
Метод с двумя строками!
Меня зовут Виктор, мой возраст - null
А вот если бы числовой параметр был примитивом int
, а не объектом ссылочного типа Integer
— такой ошибки не возникло бы.
public class Man {
public void introduce(String name, String age) {
System.out.println("Метод с двумя строками!");
System.out.println("Меня зовут " + name + ", мой возраст - " + age);
}
public void introduce(String name, int age) {
System.out.println("Метод со строкой и числом!!");
System.out.println("Меня зовут " + name + ", мой возраст - " + age);
}
public static void main(String[] args) {
Man victor = new Man();
victor.introduce("Виктор", null);
}
}
Догадался почему?
Если догадался — молодец:)
Потому что примитивы не могут быть равны null. Теперь у компилятора остался только один вариант вызова метода introduce()
— с двумя строками.
Именно этот вариант метода и будет отрабатывать каждый раз при вызове метода.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ