Алгоритмы ·
‹ Предыдущий Следующий ›
⏱ 5 минут чтения Обновлено: 2026-07-23

Метод swap в Java: обмен значениями двух переменных

swap (от англ. «менять местами») — это обмен значениями между двумя переменными: то, что лежало в первой, оказывается во второй, и наоборот. Такая операция постоянно встречается при сортировке, перестановке элементов и решении алгоритмических задач. Разберём три способа выполнить обмен в Java и отдельно — почему «метод swap» для обычных переменных в Java не работает так, как ожидают новички.

Обмен через временную переменную

Самый простой и надёжный способ. Вводим временную переменную tmp, которая сохранит значение из первой переменной, пока мы перезаписываем её значением из второй:

int tmp = a;
a = b;
b = tmp;

Полный пример:

public class SwapExample1 {
    public static void main(String[] args) {
        int a = 3;
        int b = 5;

        int tmp = a;
        a = b;
        b = tmp;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

Результат выполнения:

a = 5
b = 3

Этот вариант работает с любыми типами — int, double, String, ссылками на объекты — и не имеет подводных камней. Именно его стоит использовать по умолчанию.

Обмен без временной переменной (арифметика)

Иногда просят обменять значения без третьей переменной. Один из способов — сложение и вычитание:

a = a + b;
b = a - b;
a = a - b;

Полный пример с пошаговым разбором в комментариях:

public class SwapExample2 {
    public static void main(String[] args) {
        int a = 3;
        int b = 5;

        a = a + b; // a = 8, b = 5
        b = a - b; // a = 8, b = 3
        a = a - b; // a = 5, b = 3

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

Осторожно: переполнение

Сумма a + b может выйти за границы диапазона int (от минус 2 147 483 648 до 2 147 483 647). При переполнении промежуточный результат обрежется, и хотя итог обмена всё равно окажется верным за счёт того же переполнения при вычитании, полагаться на это в реальном коде не стоит. Для double и float арифметический трюк вообще ненадёжен из-за потери точности. Поэтому в продакшене используйте обмен через временную переменную.

Обмен через XOR

Ещё один трюк без временной переменной — побитовое исключающее ИЛИ (^). Он работает только для целочисленных типов, но не имеет проблемы переполнения:

a = a ^ b;
b = a ^ b;
a = a ^ b;

Полный пример:

public class SwapExample3 {
    public static void main(String[] args) {
        int a = 3;
        int b = 5;

        a = a ^ b;
        b = a ^ b;
        a = a ^ b;

        System.out.println("a = " + a); // a = 5
        System.out.println("b = " + b); // b = 3
    }
}

Работает это благодаря свойствам XOR: x ^ x == 0 и x ^ 0 == x. Важный нюанс: если случайно применить такой обмен к одной и той же переменной (например, arr[i] и arr[j] при i == j), она обнулится. XOR-обмен красиво смотрится на собеседовании, но в обычном коде проигрывает по читаемости варианту с временной переменной.

Почему метод swap не меняет переменные

Логично вынести обмен в отдельный метод swap. Но с примитивами это не сработает — Java всегда передаёт аргументы по значению (pass by value): метод получает копии, а не сами переменные.

public class SwapMethod {

    // НЕ работает: x и y — копии, оригиналы a и b не изменятся
    static void swap(int x, int y) {
        int tmp = x;
        x = y;
        y = tmp;
    }

    public static void main(String[] args) {
        int a = 3;
        int b = 5;
        swap(a, b);
        System.out.println("a = " + a); // a = 3
        System.out.println("b = " + b); // b = 5 — обмена не произошло
    }
}

Это одна из самых частых ловушек на собеседованиях. Написать универсальный метод swap(int, int) для двух локальных переменных в Java невозможно в принципе. Обойти ограничение можно, если передать не сами значения, а контейнер, ссылку на который можно изменить изнутри: массив, список или объект-обёртку.

Обмен элементов массива и списка

Если значения лежат в массиве, метод swap отлично работает: метод получает копию ссылки на массив, но это ссылка на тот же самый объект, поэтому изменения элементов видны снаружи.

static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

Для коллекций в стандартной библиотеке уже есть готовый метод Collections.swap, который меняет местами два элемента списка по индексам:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SwapList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("A", "B", "C"));
        Collections.swap(list, 0, 2);
        System.out.println(list); // [C, B, A]
    }
}

Что выбрать на практике

Способ Типы Плюсы Минусы
Временная переменная Любые Просто, надёжно, читаемо Нужна лишняя переменная (незначимо)
Сложение и вычитание Целые числа Без третьей переменной Риск переполнения, хуже читаемость
XOR (^) Целые числа Без переполнения, без третьей переменной Ломается при обмене элемента с самим собой
Collections.swap Элементы List Готовый метод из JDK Только для списков

Вывод простой: в реальном коде почти всегда используйте обмен через временную переменную — он понятен, работает с любыми типами и не имеет скрытых ограничений. Приёмы с арифметикой и XOR полезно знать для собеседований, но в промышленном коде они лишь усложняют чтение. А если нужно обменять значения «в вызывающем коде», помните про передачу по значению: работайте через массив, список или объект-обёртку.

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

Как написать метод swap для двух переменных в Java?

Для двух обычных (примитивных) переменных — никак: Java передаёт аргументы по значению, метод получает копии, и оригиналы не меняются. Обмен работает, только если передать контейнер — массив, List или объект-обёртку — и менять его содержимое внутри метода. Для локальных переменных выполняйте обмен напрямую, без метода.

Как поменять значения двух переменных без третьей переменной?

Двумя приёмами. Через арифметику: a = a + b; b = a - b; a = a - b; — но есть риск переполнения. Через XOR: a = a ^ b; b = a ^ b; a = a ^ b; — без переполнения, но только для целых чисел. В реальном коде удобнее и безопаснее обмен через временную переменную.

Безопасен ли обмен через сложение и вычитание?

Для целых чисел итог всегда верный, потому что переполнение при сложении компенсируется при вычитании. Но полагаться на переполнение в промышленном коде не стоит, а для double и float способ ненадёжен из-за потери точности. Предпочтительнее обмен через временную переменную.

Как обменять два элемента массива или списка?

Для массива напишите метод, принимающий массив и два индекса, и меняйте элементы через временную переменную — изменения видны снаружи, потому что метод работает с тем же объектом. Для списка используйте готовый метод Collections.swap(list, i, j).

Видео объяснение

Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.

Комментарии

Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.