在刷leetcode时看到这样一道题:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的
,这意味着在函数里修改输入数组对于调用者是可见的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
在编程语言中调用函数时的参数传递分为值传递和引用传递,在学习Java的时候一般会见过这样一句话:基本数据类型使用值传递、对象使用引用传递。
对于值传递自然好说,比如:
public void raiseSalary(int salary){
salary *= 3; //不会影响传入变量的值
}
salary接收的变量在传入函数时会拷贝一份变量作为副本,之后对这个变量的任何操作都是对副本进行操作而不会影响原变量的值,也就是说上面的这个方法是无用的。
那么为什么传入的数组对象,对其进行修改会影响原来的值呢?
首先,我们应该区分变量和对象的概念,简单地的说int[] a,a是一个数组变量。而new出来的就是一个对象。数组显然是一个对象。
int[] a = new int[]{1, 2, 3} //变量a引用了一个数组对象
在Java核心技术中已经告知,对象引用是按值传递的
,即传入的对象变量也会进行拷贝。只不过拷贝的变量也在引用原对象。即原变量和拷贝变量都会指向一个对象,所以修改这个对象,两个变量自然都可以感知到啦。
因此输入数组是以「引用」方式传递的这句话是不对的,下面的例子可以证明:
public static void main(String[] args){
int[] arrayA = new int[]{1,2,3};
int[] arrayB = new int[]{4,5,6};
System.out.println("交换前:"+Arrays.toString(arrayA)+" "+Arrays.toString(arrayB));
swapArray(arrayA,arrayB);
System.out.println("交换后:"+Arrays.toString(arrayA)+" "+Arrays.toString(arrayB));
}
public static void swapArray(int[] a,int[] b){
int[] c = a;
a = b;
b = c;
System.out.println("交换方法:"+Arrays.toString(a)+" "+Arrays.toString(b));
}
打印结果:
可以看到因为交换的是拷贝对象的引用,所以对原数组对象引用的交换并没有成功,可以参考下图,红色部分是真正进行的交换:
在大部分情况下,将对象当做引用传递可能也可以顺利解决问题。可是如果不了解背后的原理在发生错误时大概就会一头雾水了。
最后,贴一下结论:
•一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
•一个方法可以改变一个对象参数的状态。
•一个方法不能让对象参数引用一个新的对象。