近日,在复习数组排序时,定义了一个数组位置交换的wrongSwap方法,发现不可行,后来发现是java值传递和引用传递的问题。

import java.util.Arrays;
public class RankArr {

    public static void main(String[] args) {
        int[] arr = {34,11,9,0,6,78};
        int[] a = {23,312,3,44,9};
        simpleSort(arr);
        System.out.println(Arrays.toString(arr));
        bubbleSort(a);
        System.out.println(Arrays.toString(a));
    }

    public static void simpleSort(int[] arr) {

        for (int i=0;i<arr.length-1;i++) {
            for (int j=i+1;j<arr.length;j++) {
                if (arr[i]>arr[j]) {
                    swap(i,j,arr);
                }
                /*
                if (arr[i]>arr[j]) {
                    wrongSwap(arr[i],arr[j]);
                }
                */
            }
        }
    }

    public static void bubbleSort(int[] arr) {

        for (int i=0;i<arr.length-1;i++) {
            for (int j=0;j<arr.length-i-1;j++) {
                if (arr[j]>arr[j+1]) {
                    swap(j,j+1,arr);
                }
            }
        }
    }

    public static void wrongSwap(int a,int b) {
        int t = a;
        a = b;
        b = t;
    }
    public static void swap(int a,int b,int[] arr) {
        int t = arr[a];
        arr[a] = arr[b];
        arr[b] = t;
    }


}

调用wrongSwap()方法时,将数组arr其中的两个元素值作为实参传递给了方法的形参 ,这时内存的栈区创建了两个新的变量存储传递过来的值,方法中的操作实际是对这两个变量值的交换,并没有对main方法中的原数组进行操作。而swap()方法则是把main方法中的原数组引用传递过来,注意传递的是引用,而不是值,不是对象,同时把要交换的两元素下标值传递过来。然后通过引用交换数组对象两下标上的值,实现数组元素的位置互换。在这里,就引出了一个问题:java中的值传递和引用传递

在讲这个问题之前,首先要讲两组概念:
1.形参和实参:
形参:定义在方法(函数)上的参数,用来接收传递过来的实参值。
实参:出现在调用方中,可以是常量、变量、表达式和函数,但是必须被赋值。
形参在函数调用完之后在内存中被释放,形参可以接收基本数据类型值和引用:接收值时只是将原变量值复制,而引用则是将引用值(对象在内存中的虚拟首地址)传递过来,可以实现对对象的操作。

2.基本数据类型和引用类型:
基本数据类型是对一些固定存储结构数据类型的定义,是固定长度的;引用类型包括类和对象、数组、接口,引用类型较复杂,方法中创建一个引用时,此时在栈区分配了一个4byte的空间,但是还没有创建数据,当使用new运算或反射等方法创建对象时,此时就在堆区开辟空间创建数据,然后将该对象在堆内存中的虚拟首地址值赋给引用。

讲完这两组概念,其实值传递和引用传递的问题也清晰了。值传递涉及的是方法调用中基本数据类型值的传入,形参的改变并不会影响实参的改变。而引用传递是方法调用中引用的传递,并没有涉及到对象。(也有人可能会认为引用传递传递的就是引用中存储的对象堆内存地址值,但是与值传递比较值传递是将值复制一份传递,引用传递并没有复制对象,没有创建新的数据存储空间,堆内存中始终只有一个对象,从这点上看,就可以理解为什么要分为值传递和引用传递了。)然而当该引用类型值可以改变或调用了改变其自身的方法时,形参对实体对象的操作会被保存。也就是说,使用实参再次访问该对象的属性时发生了改变。

需要注意的是,某些value被final修饰的类,如String、Integer等,由于其一旦创建则不可更改,所以对形参值的改变就意味这创建了一个新的对象,而原有对象并没有改变。

我是初学者,如有错误,敬请指正!