Алгоритмы ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-07-24

Метод 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).

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.