Передача объектов в методы - Вопросы

Всего: 5 вопросов

1. 

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, переданные в метод?

Массив в 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), массив или коллекцию.

Страница 1 из 1