2014-07-04 2 views
12

Я знаю, что Java всегда проходит по значению, но я не понимаю, почему это работает:Параметр переходящая в Java

public static void swap(int[] arr, int i, int j) 
{ 
    int tmp = arr[i]; 
    arr[i] = arr[j]; 
    arr[j] = tmp; 
} 
public static void main(String[] args) 
{ 
    int[] arr = {3, 4, 5, 6}; 
    swap(arr, 1, 3); 
    // arr becomes {3, 6, 5, 4} 
} 

И это не работает:

public static void swap(int[] arr, int[] arr2) 
{ 
    int[] tmp = arr; 
    arr = arr2; 
    arr2 = tmp; 
} 
public static void main(String[] args) 
{ 
    int[] arr = {3, 4, 5, 6}; 
    int[] arr2 = {1, 2, 5, 6}; 
    swap(arr, arr2); 
} 

Почему?

+0

Вам нужно понять ссылки. –

+1

Возможный дубликат [Является ли Java «сквозной ссылкой» или «передачей по значению»?] (Http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass -by-value) – vaxquis

+1

Java передает ** ссылки ** по значению. –

ответ

14

Во втором методе, вы пытаетесь поменять ссылки, которые не будет работать, потому что сами ссылки проходят -по-значение.

Первый метод работает правильно, поскольку он изменяет объект, на который ссылается массив (который изменен), он не изменяет сама ссылка.

За дополнительной информацией о различиях между передачей по значению и передачей по ссылке обратитесь к this blog post.

+0

Я бы также добавил, что массивы изменяются в Java, поэтому первый пример работает. –

7

Ваш первый пример - перенос значений в массиве.

Второе, что вы пытаетесь изменить ссылку (массивы - объекты в Java). Ссылки являются локальными копиями (pass-by-value) и не влияют на контекст calee.

(Вопрос № 56,903 о вызове по значению; Stackexchange должен открыть PassByValue.com ;-)

+4

passbyvalue.com уже принято. – PeterMmm

+0

Большое предложение имени. :) Имеет аналогичный удар в домен, такой как SO ... – progo

3

Если вы когда-либо использовали C или C++ и знать о том, как указатели работы, то, что сделало весь этот клещ сценарий для меня является следующее утверждение:

In Java, everything is passed by value. 
In case of Objects, the reference (pointer) is passed by value. 

Так в основном функция своп

public void swap(int[] a, int[] b) 
{ 
    etc. 
} 

Будет просто получить указатель на массив int [] a и указатель на массив int [] b. Вы просто меняете два указателя. Вы не можете изменять содержимое указателей, подобных этому.

В основном C эквивалент

void swap(int* a, int* b) 
{ 
    int* temp = a; 
    a = b; 
    b = temp; 
} 

int main(void) 
{ 
    int a[] = {5,6,7,8}; 
    int b[] = {1,2,3,4}; 
    swap(a,b); 
} 

Хотя даже в C, это будет работать только как так:

void swap(int** a, int** b) 
{ 
    int* temp = (*a); 
    (*a) = (*b); 
    (*b) = temp; 
} 

int main(void) 
{ 
    int a[] = {5,6,7,8}; 
    int b[] = {1,2,3,4}; 
    swap(&a, &b); 
} 

Конечно, вы не можете отправить ссылку на ссылки в Java , Указатели в этом смысле не существуют на Java.

Следовательно, для фактического изменения объекта в другой функции вам понадобится объект «Держатель», к которому копируется ссылка, но ссылка внутри него на объект, который вы хотите изменить, на самом деле является фактической ссылкой объект, если это имело смысл.

И, таким образом, следующий будет работать:

public class ArrayHolder 
{ 
    public int[] array; 

    public ArrayHolder(int[] array) 
    { 
     this.array = array; 
    } 
} 

public void swap(ArrayHolder a, ArrayHolder b) 
{ 
    int[] temp = a.array; 
    a.array = b.array; 
    b.array = temp; 
} 

public static void main(String[] args) 
{ 
    ArrayHolder aaa = new ArrayHolder(new int[] {5,6,7,8}); 
    ArrayHolder bbb = new ArrayHolder(new int[] {1,2,3,4}); 
    swap(aaa,bbb); 
} 
1
  • Первый своп изменить данные массива.(на основании ссылки: ссылка), поэтому он изменен

  • Второй своп, вы меняете arr, arr2, две локальные переменные. поэтому при выходе из метода, новая переменная два разрушены

1
  • Arr и arr2 являются локальными переменными, так что они будут уничтожены, когда закончить метод замены.
  • Внешний метод подкачки не влияет на локальные переменные.
Смежные вопросы