Что фактически передаётся в метод Java при передаче переменной ссылочного типа?
В метод передаётся копия значения ссылки, а не сама переменная вызывающего кода и не отдельная копия объекта. Поэтому метод может изменить состояние общего изменяемого объекта, но присваивание другой ссылки локальному параметру не изменит переменную вызывающего кода.
Java использует единый механизм передачи параметров: всегда передаётся значение. Для примитивного типа копируется само значение, для ссылочного типа — значение ссылки на объект.
Такой подход отделяет переменную от объекта: переменная хранит ссылочное значение, а объект существует независимо от конкретной переменной. Метод получает собственную переменную-параметр, но она может указывать на тот же объект.
Ошибочное представление о передаче объектов приводит к двум противоположным ожиданиям. Разработчик может считать, что любое изменение параметра изменит переменную вызывающего кода, либо ожидать, что объект автоматически скопируется и исходное состояние останется неизменным.
На практике изменение полей или содержимого общего изменяемого объекта видно вызывающему коду. Переназначение параметра, напротив, действует только внутри метода. Это особенно важно для DTO, коллекций, строителей объектов и методов, изменяющих входные данные.
Пусть переменная вызывающего кода содержит ссылку на объект. При вызове метода создаётся новый параметр, в который копируется эта ссылка. Обе переменные указывают на один объект, поэтому вызов его изменяющего метода меняет общее состояние.
Если внутри метода параметру присвоить ссылку на другой объект, изменится только локальная копия ссылки. Переменная вызывающего кода по-прежнему указывает на прежний объект.
В примере value и text сначала ссылаются на один объект, поэтому append виден снаружи. После присваивания value начинает ссылаться на другой объект, но text не изменяется.
final у параметра запрещает переназначение локальной ссылки, но не делает объект неизменяемым. Также передача ссылки не означает копирование объекта: глубокую или поверхностную копию нужно создавать явно.
Если объект неизменяемый, например экземпляр неизменяемого типа, изменить его состояние через ссылку нельзя. Операция, внешне похожая на изменение, обычно создаёт новый объект и возвращает его; исходная ссылка при этом не меняется.
Метод нормализации входного DTO должен убрать лишние пробелы и заменить устаревшее значение. Рассматривались два варианта: изменить переданный изменяемый DTO на месте или создать нормализованный объект и вернуть его.
Изменение на месте проще и не требует нового объекта, но создаёт скрытый побочный эффект: тот же DTO может использоваться в журналировании, проверках или другом потоке. Создание нового объекта лучше изолирует состояние, но требует корректного копирования полей и дополнительных затрат памяти.
В коде с повторным использованием входного объекта было выбрано создание и возврат нового DTO. Это явно отражает результат операции и предотвращает зависимость вызывающего кода от случайных изменений. Если же объект является контролируемым внутренним аккумулятором и его изменение — часть контракта, допустим вариант с мутацией, но это должно быть документировано.
Дополнительный вопрос: Можно ли назвать передачу объекта в Java передачей по ссылке?
Ответ: Строго нет. В Java передаётся по значению копия ссылочного значения. Термин «передача по ссылке» обычно означает, что метод может изменить саму переменную вызывающего кода, переназначив её; такой семантики у обычных параметров Java нет.
При этом копия ссылки указывает на тот же объект, поэтому внешне поведение похоже на передачу по ссылке при изменении состояния объекта. Для точного ответа важно различать ссылку как значение и переменную, содержащую ссылку.
Дополнительный вопрос: Что изменится, если параметр объявлен как final?
Ответ: final запрещает присваивать параметру новое значение после его инициализации. Для ссылочного параметра это означает запрет переназначения ссылки, но не запрет изменения объекта, на который она указывает.
Кроме того, final не делает объект неизменяемым и не распространяется автоматически на его поля или элементы коллекции. Неизменяемость определяется контрактом самого типа и доступными операциями над его состоянием.
Дополнительный вопрос: Почему метод не может заменить объект у вызывающего кода, но может изменить его поле?
Ответ: Метод получает отдельную локальную переменную параметра. Она содержит копию исходной ссылки, поэтому присваивание новой ссылки меняет только эту локальную переменную.
До переназначения обе переменные указывают на один объект. Обращение к полю или вызов изменяющего метода выполняется через этот общий объект, поэтому изменение его состояния наблюдается через исходную переменную. Чтобы заменить объект у вызывающего кода, метод должен вернуть новую ссылку, а вызывающий код — присвоить её своей переменной.