← Назад к вопросам

Как реализована передача параметров в Java?

2.7 Senior🔥 251 комментариев
#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как реализована передача параметров в Java

Pass-by-value — это фундаментальный механизм Java, означающий, что все параметры передаются по значению (копии), а не по ссылке. Это часто вызывает путаницу, особенно при работе с объектами. Важно понимать разницу между копией ссылки и копией объекта.

Основной принцип: Pass-by-Value

Java ВСЕГДА передаёт копию значения:

public class PassByValueExample {
    public static void main(String[] args) {
        int age = 25;
        modifyValue(age);
        System.out.println(age);  // 25 — не изменилось
    }
    
    static void modifyValue(int value) {
        value = 30;  // Меняем копию, оригинал не меняется
    }
}

Метод получает копию переменной, поэтому изменение в методе не влияет на оригинальную переменную.

Примитивные типы (int, boolean, double и т.д.)

Для примитивов всё понятно — передаётся копия значения:

public class PrimitiveExample {
    public static void main(String[] args) {
        int x = 10;
        double y = 3.14;
        boolean flag = true;
        
        modifyPrimitives(x, y, flag);
        
        System.out.println(x);      // 10 — не изменилось
        System.out.println(y);      // 3.14 — не изменилось
        System.out.println(flag);   // true — не изменилось
    }
    
    static void modifyPrimitives(int num, double decimal, boolean bool) {
        num = 20;
        decimal = 2.71;
        bool = false;  // Изменения только в локальной копии
    }
}

Объекты: передача ссылки по значению

Для объектов ситуация сложнее. Ссылка на объект передаётся по значению — копируется сама ссылка, а не сам объект:

public class Person {
    String name;
    int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class ReferenceExample {
    public static void main(String[] args) {
        Person person = new Person("John", 25);
        
        modifyPerson(person);
        
        // ПОЛЕ ИЗМЕНИЛОСЬ
        System.out.println(person.name);  // "Jane" — изменилось!
        System.out.println(person.age);   // 25 — не изменилось
    }
    
    static void modifyPerson(Person p) {
        p.name = "Jane";  // Меняем поле объекта через ссылку
        p.age = 30;       // Меняем поле объекта
        
        // Но если переассигнить саму ссылку — эффекта снаружи не будет
        p = new Person("Bob", 40);  // Это не повлияет на оригинальную ссылку
    }
}

Важно: мы меняем поля объекта, но саму ссылку в методе modifyPerson переассигнить нельзя (копия ссылки).

Визуализация: примитив vs объект

public class PassByValueVisualization {
    static class Box {
        int value = 10;
    }
    
    public static void main(String[] args) {
        // Примитив
        int num = 5;
        // Stack: [num=5]
        
        // Объект
        Box box = new Box();
        // Stack: [box ссылка] → Heap: [Box объект, value=10]
        
        modifyBoth(num, box);
        // Метод получает копии: num=5 и box (копию ссылки)
        
        System.out.println(num);        // 5 — не изменилось
        System.out.println(box.value);  // 20 — изменилось!
    }
    
    static void modifyBoth(int n, Box b) {
        n = 15;      // Меняем копию примитива → снаружи не видно
        b.value = 20;  // Меняем объект через копию ссылки → видно снаружи
        
        b = null;    // Переассигнение копии ссылки → снаружи не видно
    }
}

Классический пример с переассигнением

public class ReferenceReassignment {
    static class Car {
        String model;
        
        Car(String model) {
            this.model = model;
        }
    }
    
    public static void main(String[] args) {
        Car myCar = new Car("BMW");
        
        changeCar(myCar);
        
        System.out.println(myCar.model);  // "BMW" — не "Audi"!
    }
    
    static void changeCar(Car car) {
        // Этот код НЕ повлияет на myCar снаружи
        car = new Car("Audi");  // Переассигнили копию ссылки
        
        // А это повлияет
        car.model = "Mercedes";  // Меняем объект через ссылку
    }
}

Меньше повезло с переассигнением — это менял только локальную копию ссылки.

Как вернуть изменённый объект

Если нужно "вернуть" изменённый объект, используй return:

public class ReturnModifiedObject {
    static class Person {
        String name;
        Person(String name) {
            this.name = name;
        }
    }
    
    public static void main(String[] args) {
        Person person = new Person("John");
        
        // Способ 1: Возвращаем новый объект
        person = changePerson(person);
        System.out.println(person.name);  // "Jane"
        
        // Способ 2: Меняем поле напрямую
        modifyField(person);
        System.out.println(person.name);  // "Bob"
    }
    
    // Возвращаем новый объект
    static Person changePerson(Person p) {
        return new Person("Jane");
    }
    
    // Меняем поле через ссылку
    static void modifyField(Person p) {
        p.name = "Bob";
    }
}

Практические последствия

1. Безопасность: невозможно случайно переассигнить параметр

public class SafetyExample {
    static void setValue(String value) {
        value = "new";  // Меняет только локальную копию
    }
    
    public static void main(String[] args) {
        String text = "old";
        setValue(text);
        System.out.println(text);  // "old" — не изменилось
    }
}

2. Изменяемость объектов (mutable)

public class MutableExample {
    static void clearList(List<String> list) {
        list.clear();  // Очищаем исходный список!
    }
    
    public static void main(String[] args) {
        List<String> items = new ArrayList<>();
        items.add("Item1");
        
        clearList(items);
        System.out.println(items.size());  // 0 — список очищен!
    }
}

3. Неизменяемость объектов (immutable)

public class ImmutableExample {
    public static void main(String[] args) {
        String text = "Hello";
        String modified = text.toUpperCase();  // Новая строка
        
        System.out.println(text);        // "Hello" — не изменилось
        System.out.println(modified);    // "HELLO"
    }
}
String в Java **immutable**, поэтому строки всегда безопасны при передаче в методы.

Таблица: Pass-by-Value в разных сценариях

ТипПередаётсяМожет измениться снаружи
int, double, booleanКопия значенияНЕТ
StringКопия ссылки (но String immutable)НЕТ
List, ArrayКопия ссылкиДА (содержимое)
ObjectКопия ссылкиДА (поля)
Ссылка (переассигнение)Копия ссылкиНЕТ

Итоговый вывод

Java всегда использует pass-by-value:

  • Для примитивов — копируется само значение
  • Для объектов — копируется ссылка, но это позволяет менять поля объекта
  • Переассигнение параметра внутри метода не видно снаружи

Это один из важнейших концептов Java, необходимый для понимания поведения программы.

Как реализована передача параметров в Java? | PrepBro