1. введение
Двумя наиболее распространенными способами передачи аргументов методам являются “передача по значению” и “передача по ссылке”. Различные языки программирования используют эти понятия по-разному. Что касается Java, все строго Pass-by-Value .
В этом уроке мы проиллюстрируем, как Java передает аргументы для различных типов.
2. Pass-by-Value vs Pass-by-Reference
Давайте начнем с некоторых различных механизмов передачи параметров функциям:
- ценность
- ссылка
- результат
- значение-результат
- имя
Двумя наиболее распространенными механизмами в современных языках программирования являются “Передача по значению” и “Передача по ссылке”. Прежде чем мы продолжим, давайте сначала обсудим это:
2.1. Передача по значению
Когда параметр передается по значению, вызывающий и вызываемый метод работают с двумя различными переменными, которые являются копиями друг друга. Любые изменения одной переменной не изменяют другую.
Это означает, что при вызове метода параметры , передаваемые вызываемому методу, будут клонами исходных параметров. Любая модификация, выполненная в методе вызываемого абонента, не повлияет на исходные параметры в методе вызывающего абонента.
2.2. Пропуск по ссылке
Когда параметр передается по ссылке, вызывающий и вызываемый объект работают с одним и тем же объектом.
Это означает, что при передаче переменной по ссылке методу отправляется уникальный идентификатор объекта. Любые изменения членов экземпляра параметров приведут к изменению исходного значения.
3. Передача параметров в Java
Фундаментальными понятиями в любом языке программирования являются “значения” и “ссылки”. В Java примитивные переменные хранят фактические значения, в то время как непримитивы хранят ссылочные переменные, которые указывают на адреса объектов, на которые они ссылаются. Как значения, так и ссылки хранятся в памяти стека.
Аргументы в Java всегда передаются по значению. Во время вызова метода копия каждого аргумента, будь то значение или ссылка, создается в памяти стека, которая затем передается методу.
В случае примитивов значение просто копируется в память стека, которая затем передается вызываемому методу; в случае непримитивов ссылка в памяти стека указывает на фактические данные, которые находятся в куче. Когда мы передаем объект, ссылка в памяти стека копируется, и новая ссылка передается методу.
Давайте теперь посмотрим на это в действии с помощью некоторых примеров кода.
3.1. Передача Примитивных Типов
Язык программирования Java имеет восемь примитивных типов данных . Примитивные переменные непосредственно хранятся в памяти стека. Всякий раз, когда какая-либо переменная примитивного типа данных передается в качестве аргумента, фактические параметры копируются в формальные аргументы, и эти формальные аргументы накапливают свое собственное пространство в памяти стека.
Срок службы этих формальных параметров длится только до тех пор, пока этот метод работает, и после возврата эти формальные аргументы удаляются из стека и отбрасываются.
Давайте попробуем разобраться в этом с помощью примера кода:
public class PrimitivesUnitTest { @Test public void whenModifyingPrimitives_thenOriginalValuesNotModified() { int x = 1; int y = 2; // Before Modification assertEquals(x, 1); assertEquals(y, 2); modify(x, y); // After Modification assertEquals(x, 1); assertEquals(y, 2); } public static void modify(int x1, int y1) { x1 = 5; y1 = 10; } }
Давайте попробуем понять утверждения в приведенной выше программе, проанализировав, как эти значения хранятся в памяти:
- Переменные ” x” и ” y” в основном методе являются примитивными типами, и их значения непосредственно хранятся в памяти стека
- Когда мы вызываем метод modify() , точная копия для каждой из этих переменных создается и хранится в другом месте в памяти стека
- Любое изменение этих копий влияет только на них и оставляет исходные переменные неизменными
3.2. Передача ссылок на объекты
В Java все объекты динамически хранятся в пространстве кучи под капотом. Эти объекты ссылаются на ссылки, называемые ссылочными переменными.
Объект Java, в отличие от примитивов, хранится в два этапа. Ссылочные переменные хранятся в памяти стека, а объект, на который они ссылаются, хранится в памяти кучи.
Всякий раз, когда объект передается в качестве аргумента, создается точная копия ссылочной переменной, которая указывает на то же расположение объекта в памяти кучи, что и исходная ссылочная переменная.
В результате этого всякий раз, когда мы вносим какие-либо изменения в один и тот же объект в методе, это изменение отражается в исходном объекте. Однако, если мы выделим новый объект для переданной ссылочной переменной, то он не будет отражен в исходном объекте.
Давайте попробуем понять это с помощью примера кода:
public class NonPrimitivesUnitTest { @Test public void whenModifyingObjects_thenOriginalObjectChanged() { Foo a = new Foo(1); Foo b = new Foo(1); // Before Modification assertEquals(a.num, 1); assertEquals(b.num, 1); modify(a, b); // After Modification assertEquals(a.num, 2); assertEquals(b.num, 1); } public static void modify(Foo a1, Foo b1) { a1.num++; b1 = new Foo(1); b1.num++; } } class Foo { public int num; public Foo(int num) { this.num = num; } }
Давайте проанализируем утверждения в приведенной выше программе. Мы передали объекты a и b в modify() метод, который имеет то же значение 1 . Первоначально эти ссылки на объекты указывают на два различных местоположения объектов в пространстве кучи:
Когда эти ссылки a и b передаются в методе modify () , он создает зеркальные копии этих ссылок a1 и b1 , которые указывают на одни и те же старые объекты:
В методе modify () , когда мы изменяем ссылку a1 , он изменяет исходный объект. Однако для ссылки b1, мы назначили новый объект. Таким образом, теперь он указывает на новый объект в памяти кучи.
Любое изменение, внесенное в b1 , ничего не отразит в исходном объекте:
4. Заключение
В этой статье мы рассмотрели, как обрабатывается передача параметров в случае примитивов и непримитивов.
Мы узнали, что передача параметров в Java всегда происходит по значению. Однако контекст меняется в зависимости от того, имеем ли мы дело с примитивами или объектами:
- Для примитивных типов параметры передаются по значению
- Для типов объектов ссылка на объект является передаваемым значением
Фрагменты кода, используемые в этой статье, можно найти на GitHub .