В Java передаются параметры по ссылке или по значению?
Короткий ответ: в Java всегда передача по значению
Запомните главное правило: Java всегда передаёт параметры по значению. Никакой передачи по ссылке в Java нет. Путаница возникает из-за того, что начинающие программисты неправильно понимают, что именно является "значением" при работе с объектами.
Что такое "значение" для примитивов и объектов?
Для примитивных типов (int, double, boolean и т.д.) значение — это сам байт данных. Вы передаёте копию числа, и изменения внутри метода не влияют на оригинал:
public class Test {
public static void main(String[] args) {
int x = 10;
changePrimitive(x);
System.out.println(x); // Вывод: 10 (не изменилось)
}
public static void changePrimitive(int value) {
value = 20; // меняем копию
}
}
Для ссылочных типов (объекты, массивы, строки) "значением" является ссылка (адрес в памяти), а не сам объект. Когда вы передаёте объект в метод, вы передаёте копию этой ссылки. Обе ссылки (оригинальная и копия) указывают на один и тот же объект в куче.
Почему первый пример работает?
В первом примере вы передаёте копию ссылки на StringBuilder. Оригинальная ссылка sb и копия s указывают на один и тот же объект. Вызов s.append(" World") изменяет содержимое этого объекта. Поскольку оригинальная ссылка sb всё ещё указывает на тот же объект, изменения видны снаружи.
Почему второй пример не работает?
Во втором примере вы присваиваете копии ссылки s новый объект: s = new StringBuilder("World"). Это не меняет объект, на который указывает s, а заставляет s указывать на совершенно другой объект. Оригинальная ссылка sb продолжает указывать на старый объект "Hello".
Ключевой момент: вы не можете изменить саму ссылку снаружи. Вы можете только изменить объект, на который ссылка указывает (если объект мутабельный).
Наглядная аналогия
- Передача по значению — это как дать кому-то копию адреса вашего дома. Этот человек может прийти и перекрасить стены внутри дома (изменить объект), но не может заставить вас переехать в другой дом (изменить вашу ссылку).
- Передача по ссылке (как в C++) — это дать кому-то сам ключ от вашего дома. Этот человек может не только перекрасить стены, но и сказать: "Ты теперь живёшь в другом доме", и вы действительно переедете.
Как проверить себя?
Если бы Java поддерживала передачу по ссылке, то второй пример изменил бы sb на новый объект. Этого не происходит, значит, передача только по значению.
Итог
Запомните три правила:
- Java всегда передаёт параметры по значению (копию значения).
- Для примитивов значением является само число.
- Для объектов значением является ссылка (адрес в памяти).
Когда вы говорите "передача по ссылке" в контексте Java — это ошибка. Правильно говорить: "передача ссылки по значению".
<<Дополнение: как это связано с неизменяемыми объектами
Путаница часто усиливается при работе с неизменяемыми (immutable) объектами, например, со строками String. Поскольку String нельзя изменить, любые "изменения" на самом деле создают новый объект:
public class Test {
public static void main(String[] args) {
String str = "Hello";
changeString(str);
System.out.println(str); // Вывод: Hello
}
public static void changeString(String s) {
s = s + " World"; // Создаётся новый объект, s теперь указывает на него
}
}
Здесь s = s + " World" создаёт новый объект String и присваивает его копии ссылки s. Оригинальная ссылка str по-прежнему указывает на "Hello". Это работает точно так же, как и с мутабельными объектами — вы не можете изменить ссылку снаружи.
Совет для новичков: если хотите изменить объект внутри метода и чтобы изменения были видны снаружи, убедитесь, что:
- Объект мутабельный (можно изменять его содержимое).
- Вы не присваиваете параметру новый объект, а вызываете методы, изменяющие состояние текущего объекта.
Если нужно изменить саму ссылку (например, заменить объект на новый), придётся возвращать новое значение из метода или использовать обёртки/массивы.