ООП ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-07-25

Перегрузка методов и конструкторов в Java

Перегрузка методов (method overloading) в Java — это возможность объявить в одном классе несколько методов с одинаковым именем, но разными списками параметров. Компилятор сам выбирает подходящую версию по типам и количеству аргументов. Тот же приём работает и для конструкторов. Разберём правила, примеры и случаи, где перегрузка ведёт себя неожиданно.

1. Что такое перегрузка методов в Java

В Java разрешается в одном и том же классе определять два или более метода с одним именем, если объявления их параметров отличаются. Это и называется перегрузкой методов. Параметры могут отличаться:

  • количествомtest(int a) и test(int a, int b);
  • типомtest(int a) и test(String a);
  • порядком типовtest(int a, String b) и test(String a, int b).

Имена параметров при этом роли не играют: test(int a) и test(int value) — это один и тот же метод с точки зрения компилятора.

В следующем примере класс объявляет два метода с одним именем test, но разными параметрами:

public class OverloadingExample1 {
    void test(int a) {
        System.out.println("a: " + a);
    }

    void test(int a, int b) {
        System.out.println("a и b: " + a + " " + b);
    }

    public static void main(String[] args) {
        OverloadingExample1 ob = new OverloadingExample1();

        ob.test(10);      // a: 10
        ob.test(10, 20);  // a и b: 10 20
    }
}

Комбинация имени метода и типов его параметров образует сигнатуру метода. Внутри одного класса сигнатуры должны быть уникальными — именно по сигнатуре и различаются перегруженные варианты.

Перегрузка методов — один из способов поддержки полиморфизма в Java. Её называют статическим (или compile-time) полиморфизмом, потому что решение о вызываемом методе принимается ещё до запуска программы.

Важно

Перегруженный метод выбирает компилятор, а не JVM. Уже на этапе компиляции в байт-код записывается конкретная сигнатура, поэтому во время выполнения ничего «доопределяться» не будет. Решение принимается по объявленным типам аргументов, а не по их фактическим типам в памяти.

2. Возвращаемый тип и перегрузка

Возвращаемые типы перегруженных методов могут отличаться, но самого возвращаемого типа недостаточно, чтобы отличить два варианта метода: он не входит в сигнатуру.

В примере ниже методы void test() и double test(double a) возвращают значения разного типа — это допустимо, потому что различаются параметры. А закомментированный int test() отличается от void test() только типом результата, и его добавление приведёт к ошибке компиляции method test() is already defined:

public class OverloadingExample2 {
    void test() {
        System.out.println("Без параметров");
    }

    // Неправильная перегрузка: отличается только возвращаемый тип
    /* int test() {
        System.out.println("Без параметров");
        return 1;
    }*/

    double test(double a) {
        System.out.println("double a: " + a);
        return a * a;
    }

    public static void main(String[] args) {
        OverloadingExample2 ob = new OverloadingExample2();

        ob.test();
        double result = ob.test(123.25);
        System.out.println("Результат вызова метода ob.test(123.25): " + result);
    }
}

По той же причине не образуют перегрузку методы, различающиеся только модификатором доступа (public/private), модификатором static, final или списком throws.

3. Перегрузка конструкторов

Конструкторы устроены так же, как методы, поэтому они тоже могут быть перегружены: в одном классе допустимо объявить несколько конструкторов, различающихся количеством, типом или порядком параметров. При создании объекта вызывается ровно один из них — тот, что соответствует переданным аргументам.

В следующем примере в класс Box6 добавлены три конструктора:

public class Box6 {
    double width;
    double height;
    double depth;

    Box6(double w, double h, double d) {
        width = w;
        height = h;
        depth = d;
    }

    Box6() {
        // -1 условно обозначает "размеры не заданы"
        width = -1;
        height = -1;
        depth = -1;
    }

    Box6(double len) {
        width = len;
        height = len;
        depth = len;
    }

    double getVolume() {
        return width * height * depth;
    }
}
public class OverloadCons {
    public static void main(String[] args) {
        Box6 myBox1 = new Box6(10, 20, 15); // три параметра
        Box6 myBox2 = new Box6();           // без параметров
        Box6 myBox3 = new Box6(7);          // куб со стороной 7

        System.out.println("Объем myBox1: " + myBox1.getVolume()); // 3000.0
        System.out.println("Объем myBox2: " + myBox2.getVolume()); // -1.0
        System.out.println("Объем myBox3: " + myBox3.getVolume()); // 343.0
    }
}

Обратите внимание на new Box6(7): передаётся литерал типа int, а конструктор принимает double. Работает то же расширение примитивного типа, что и для методов, поэтому отдельная версия с int не нужна.

Значение -1 здесь — учебный маркер «размеры не заданы». В реальном коде лучше не изобретать магические числа, а задать разумные значения по умолчанию, вынеся общую логику в один конструктор и вызывая его через this(...):

public class Box7 {
    double width;
    double height;
    double depth;

    Box7(double w, double h, double d) {
        width = w;
        height = h;
        depth = d;
    }

    Box7() {
        this(1, 1, 1);   // единичный куб по умолчанию
    }

    Box7(double len) {
        this(len, len, len);
    }
}

Вызов this(...) должен быть первой инструкцией конструктора (до Java 22 — строго первой; начиная с Java 22 перед ним допустим код, не обращающийся к создаваемому объекту). Такой приём называют делегированием конструкторов: логика инициализации описана в одном месте, остальные конструкторы лишь подставляют значения по умолчанию.

4. Неочевидные моменты перегрузки

  • Не перегружайте ради перегрузки. Если методы делают разные вещи, дайте им разные имена: parseFromFile и parseFromString читаются лучше, чем два parse с похожими параметрами.

Совет на собеседование

Формулировка «перегрузка — это полиморфизм времени выполнения» — ошибка, на которой ловятся чаще всего. Правильный ответ: перегрузка разрешается статически, компилятором; динамически, по фактическому типу объекта, разрешается только переопределение.

5. Коротко о главном

  • Перегрузка — несколько методов с одним именем и разными списками параметров в одном классе.
  • Различать варианты можно количеством, типом или порядком параметров; возвращаемым типом, модификаторами и throws — нельзя.
  • Конструкторы перегружаются по тем же правилам; общую инициализацию удобно выносить в один конструктор и вызывать его через this(...).
  • Перегрузка — статический полиморфизм, переопределение — динамический.

Часто задаваемые вопросы

Можно ли перегрузить методы, которые отличаются только типом возвращаемого значения?

Нет. Возвращаемый тип не входит в сигнатуру метода, поэтому int test() и void test() в одном классе дадут ошибку компиляции «method test() is already defined». Различаться должны параметры: их количество, типы или порядок.

Можно ли перегрузить метод main?

Да, в классе может быть сколько угодно методов с именем main и разными параметрами. Но точкой входа JVM считает только public static void main(String[] args); остальные версии вы вызываете из кода сами, как обычные методы.

Video Explanation

Prefer video format? Watch this lesson with examples and explanations.

Comments

Please log in or register to have a possibility to add comment.