Передача объектов в методы - Вопросы
Всего: 5 вопросов
1. Java передаёт объекты в методы по ссылке или по значению?
Java передаёт объекты в методы по ссылке или по значению?
Java всегда передаёт аргументы только по значению (pass-by-value). Для примитивного параметра копируется само значение, для объектного — копия ссылки, то есть адрес объекта в куче. Копия ссылки указывает на тот же самый объект, поэтому метод может изменить его состояние, и это увидят все, кто держит ссылку на объект. Но заставить переменную вызывающего кода указывать на другой объект метод не может. Передачи по ссылке (pass-by-reference), как в C++ или C#, в Java нет; распространённая фраза «объекты передаются по ссылке» — удобное упрощение, которое на собеседовании стоит уточнять.
2. Почему изменения полей объекта, сделанные внутри метода, видны в вызывающем методе, а изменения примитивного параметра — нет?
Почему изменения полей объекта, сделанные внутри метода, видны в вызывающем методе, а изменения примитивного параметра — нет?
При вызове метода в стеке выделяется новый блок памяти с локальными переменными-параметрами. Для примитива туда копируется само значение: параметр и переменная вызывающего кода — разные ячейки памяти, поэтому a *= 2; внутри метода не влияет на x снаружи. Для объекта в стеке метода лежит только копия ссылки, а сам объект живёт в куче в единственном экземпляре. Обращение box.width *= 2; меняет объект в куче, и вызывающий код, который смотрит на тот же объект, видит новое значение. Пример:
static void changeObject(Box box) {
box.width *= 2; // видно в main()
}
static void changePrimitives(int a) {
a *= 2; // НЕ видно в main()
}
3. Почему присваивание параметру нового объекта внутри метода не видно в вызывающем коде?
Почему присваивание параметру нового объекта внутри метода не видно в вызывающем коде?
Потому что параметр — это локальная копия ссылки. Строка box = new Box(1, 1, 1); заставляет указывать на новый объект только эту копию; переменная вызывающего кода продолжает ссылаться на прежний объект. Если бы объекты передавались по ссылке, переменная снаружи тоже «переехала» бы на новый объект — но в Java этого не происходит:
static void reassign(Box box) {
box = new Box(1, 1, 1); // меняется только локальная копия ссылки
box.width = 100;
}
static void mutate(Box box) {
box.width = 100; // меняется объект, созданный в main()
}
после reassign: 5.0
после mutate: 100.0
Отсюда же следует, что метод swap() не может поменять местами две переменные вызывающего кода: он переставляет только свои локальные параметры.
4. Как ведут себя массив, String и StringBuilder, переданные в метод?
Как ведут себя массив, String и StringBuilder, переданные в метод?
Массив в Java — обычный объект, поэтому запись numbers[0] = 42; внутри метода меняет тот же массив, и вызывающий код увидит новое значение. То же верно для StringBuilder и коллекций: builder.append(" Java") изменяет сам объект. А String неизменяем (immutable): выражение text += " Java" создаёт новую строку и присваивает её локальному параметру, оригинал остаётся прежним. Если строку нужно «нарастить» внутри метода — используйте StringBuilder или возвращайте результат из метода.
numbers[0]: 42
text: Hello
builder: Hello Java
5. Что возвращает метод, у которого тип возвращаемого значения — класс, и что происходит с объектом, созданным внутри метода?
Что возвращает метод, у которого тип возвращаемого значения — класс, и что происходит с объектом, созданным внутри метода?
Возвращается ссылка на объект в куче — сам объект при возврате не копируется. Объект, созданный внутри метода, не исчезает после выхода из него: он живёт в куче ровно до тех пор, пока на него есть хотя бы одна ссылка, а затем его освободит сборщик мусора.
ReturnObjectExample incrementByTen() {
return new ReturnObjectExample(a + 10); // возвращается ссылка на новый объект
}
ReturnObjectExample ob1 = new ReturnObjectExample(2);
ReturnObjectExample ob2 = ob1.incrementByTen();
System.out.println(ob1.a + " " + ob2.a); // 2 12
Таким же способом из метода «возвращают несколько значений»: их упаковывают в объект-контейнер — собственный класс, record (начиная с Java 16), массив или коллекцию.