Он выводит 0
, потому что это значение a
в функции main
. Java является полностью передачей по значению, она вообще не имеет передачи по ссылке. Поэтому, когда вы вызываете foo
, значение переменной a
передается в foo
, а не является ссылкой на переменную a
. foo
затем изменяет значение его аргумента a
, но это никак не влияет на переменную a
в main
.
Вы можете услышать, как люди говорят о «передаче по значению» или «передаче по значению ссылки», что может ввести в заблуждение, и я настоятельно рекомендую избегать такой терминологии, как чума. :-) Но вот что они говорят:
В вашем примере a
является примитивом . Переменная a
содержит значение 0
. Но в равной степени вы могли бы сделать это:
Object a = new Object();
foo(a);
Что теперь передается foo
? Точно то же самое, что было передано, когда оно было int
: значение из a
. Единственное отличие состоит в том, что теперь значение из a
является ссылкой на объект. Ссылки на объекты - это просто значения, как и все остальное; они сообщают JVM, где данные для объекта находятся в памяти. Думайте о них как о индексах в большом массиве или о чем-то.
Так где:
int a = 42;
дает нам это в памяти:
+---------+
| a |
+---------+
| 42 |
+---------+
это
Object a = new Object();
... дает нам это:
+---------+
| a |
+---------+ +-----------------+
| mumble |------------>| The object data |
+---------+ +-----------------+
Важно понимать, что a
все еще просто содержит значение, так же, как когда оно содержит int
или float
. Это просто значение этого значения, которое отличается, так же как значение значения, содержащегося в int
, отличается от значения значения, содержащегося в float
. В случае ссылки на объект значение значения означает «объект находится там».
Так же, как вы можете иметь более одной переменной, содержащей значение 42
, вы можете иметь более одной переменной, содержащей ссылку на один и тот же объект:
int a, b;
a = 42;
b = a;
дает нам
+---------+ +---------+
| a | | b |
+---------+ +---------+
| 42 | | 42 |
+---------+ +---------+
и аналогично
Object a, b;
a = new Object();
b = a;
дает нам
+----------+ +----------+
| a | | b |
+----------+ +----------+
| mumble |--+--| mumble |
+----------+ | +----------+
|
|
| +-----------------+
+--->| The object data |
+-----------------+
a
и b
все еще содержат значения, например 42; но это значение сообщает JVM, где находится объект, и поэтому они ссылаются (указывают на) на один и тот же объект.
Возвращаясь к foo
, когда вы вызываете функцию, передача аргумента в точности аналогична присвоению переменной другой переменной, поэтому представьте b
выше как аргумент функции foo
.
В комментариях ниже вы спрашивали о массивах. Массивы похожи на объекты & mdash; или они являются объектами; выберите предпочитаемую семантику :-) Итак:
int[] a;
int[] b;
a = new int[5];
b = a;
дает нам:
+----------+ +----------+
| a | | b |
+----------+ +----------+
| mumble |--+--| mumble |
+----------+ | +----------+
|
|
| +----------------+
+--->| The array data |
+----------------|
| [0]: 0 |
| [1]: 0 |
| [2]: 0 |
| [3]: 0 |
| [4]: 0 |
+----------------+
Итак, рассмотрим:
public static final void main(String[] args) {
int[] a = new int[5];
foo(a);
System.out.println(a[0]);
}
void foo(int[] b) {
b[0] = 42;
}
Это печатает 42
. Зачем? Поскольку значение из a
было передано в foo
, и поэтому b
в пределах foo
указывает на тот же массив, на который указывает a
. Вы можете изменить состояние объекта, используя ссылку. Обратите внимание, что вы не изменяете значение b
, вы меняете состояние вещи, к которой относится b
.
Контрастность с:
public static final void main(String[] args) {
int[] a = new int[5];
foo(a);
System.out.println(a[0]);
}
void foo(int[] b) {
b = new int[5]; // <==== change here
b[0] = 42;
}
Теперь он печатает 0
, потому что вы присвоили новое значение (новая ссылка на объект) на b
, что не влияет на значение, хранящееся в a
или вещи что значение a
относится к.