Java中方法的传参问题----传值

创作缘由

传值:形参取的是实参的值,形参的改变不会导致调用点所传的实参的值发生改变。
传址:形参取的是实参的地址,即相当于实参存储单元的地址引用,因此此值的改变同时就改变了实参的值。
方法的传参相信是每个程序员都必了解的问题,也是最基本的一个知识点。但是,学习编程近两年的我今天竟然跪在了Java的参数传递上。具体问题见下:

问题

在学习数据结构时,我写了一个数组的缩容的操作,即当数组数据量量减少一遍时,那么相应的数组的长度也减少一半。

我的想法很简单,当删除方法内元素时,进行一次数组内容量的判断,如果小于一半,则调用缩容的方法。缩容的方法进行了封装,以便于我之后复用。

我的代码:

  //删除数组的最后一个元素
    public void removeLast() {
    
    
        this.remove(size - 1);
    }
    //删除数据指定位置的元素
    public void remove(int index) {
    
    
        if (index < 0 || index >= size) {
    
    
            throw new IllegalArgumentException("Remove failes. Array is out of index.");
        }
        //移除指定位置的元素
        for (int i = index; i < size - 1; i++) {
    
    
            this.array[index] = this.array[index + 1];
        }
        size--;
        if (size < this.array.length / 2) {
    
    
            reduceArray(this.array);
        }
    }
    //数组的缩容
    public void reduceArray(int[] array) {
    
    
        int length = array.length / 2;
        int[] newArray = new int[length];
        for (int i = 0; i < length; i++) {
    
    
            newArray[i] = array[i];
        }
        array = newArray;
    }

执行

因为数组的默认容量为10,所以当我移除元素时,会调用缩容方法

       //缩容
        Array array1 = new Array();
        array1.addLast(1);
        array1.addLast(2);
        array1.addLast(3);
        array1.removeLast();
        System.out.println(array1.getLength());

结果:根据我的判断,控制台应该打印5,但是实际上,控制台打印数组的长度为10

我进行了debug,发现,当我将数组传递至reduceArray(int[] array)这个方法内时,此时array并不是我传递进来的那个数组,而是又新建了一个数组。
在这里插入图片描述
所以最后的结果:我传入的数据并没有缩容,而作为参数传入新建的数组,进行了缩容。
在这里插入图片描述

方法的参数传递机制

如果声明方法时,包含了形参声明,则调用方法时必须给这些形参指定参数值,调用方法时实际传给形参的参数值被称为实参。
Java参数传递方式只有一种:值传递(重要!!!!)
值传递:将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响。

参数为基本数据类型

    public static void main(String[] args) {
    
    
        int a = 6;
        int b = 9;
        swap(a,b);
        System.out.println("a:" + a + "b" + b);  // a:6b9
    }

    public static void swap(int a, int b) {
    
    
        int temp = a;
        a = b;
        b = temp;
        System.out.println("a:" + a + "b" + b);  // a:9b6
    }

当a,b以实参的形式传递进swap方法内时,此时Java程序会创建二者的副本,swap方法内a,b值的改变并不会影响实际的a和b的值。
在这里插入图片描述
在这里插入图片描述
a,b交换示意图
在这里插入图片描述
因此,方法中ab值的交换并不会影响实际a,b的值。

参数为引用数据类型

    public static void main(String[] args) {
    
    
        DataWrap dw = new DataWrap();
        dw.a = 6;
        dw.b = 9;
        swap(dw);
        System.out.println("a:" + dw.a + "b:" + dw.b);

    }

    public static void swap(DataWrap dw) {
    
    
        int temp = dw.a;
        dw.a = dw.b;
        dw.b = dw.a;
        System.out.println("a:" + dw.a + "b:" + dw.b);
    }
}

	class DataWrap {
    
    
	    int a;
	    int b;
	}

从运行结果看,在swap()方法里,a,b两个成员变量的值被交换成功。当swap()方法执行完后,main()方法中的值也被交换了。 错觉:调用swap()方法时,传入swap()方法的就是dw对象本身,并不是它的复制品。 这是错误的。
在这里插入图片描述
由此可以看出,引用类型传递时,是将对象的地址值传入了进去,因此形参复制的是地址值,而非赋值的原对象。因此当改变对象的属性时,实际还是改变了同一对象的值。因为原dw与复制的dw二者所指向的对象都是同一个。
在这里插入图片描述
将swap()中的dw=null;
此时,我们只是把副本的地址值设置为了null,而并非把实际的dw设置为了null,所以此时dw还是有值的。
在这里插入图片描述
在这里插入图片描述

字符串类型的交换

字符串作为引用类新过的变量,我们进行传参操作时,是否也和引用类型一样呢?

 		String a = new String("123456");
 		 System.out.println(a); //123456
        StringTest.change(a);
        System.out.println(a); //123456

    public static void change(String a) {
    
    
       a.concat("123456");
    }
  • 因为字符串底层是final类型的char[]数组,所以字符串的值是不可改变的,所以当我们concat()的时候(或其他修改字符串的方法时),String背后又为我们创建了一个新的String返回。a作为参数传递进来,concat之后,此时传递进来的a指向一个新的字符串对象。原字符串的值没有发生改变。所以原来的a指向的字符串的值没有发生变化。

总结

  1. Java是进行值传递的
  2. 值传递实际:当系统开始执行方法时,系统为形参执行初始化,就是把实参变量的值赋给方法的形参变量,方法里操作的并不是实际的实参的变量。
  3. 对于基本类型来说,参数传递后值的修改不会影响原来的值。(形参与实参指向值所在的存储空间不同,所以形参指向的值的改变并不影响实参指向的值)
  4. 对于引用类型来说,参数传递后对象的引用修改不会影响原来的值。(形参指向新创建的对象,实参还是指向原来的对象,所以实参的值并不会改变)
  5. 对于引用类型来说,参数传递后更改对象的属性值会影响原来对象的相关属性值。(当形参改变对象的值时,实参指向对象同步变化。因为二者共用一个对象)

Guess you like

Origin blog.csdn.net/zhang19903848257/article/details/118674108