Java和C++在函数参数传递上的不同

来源:互联网 发布:淘宝玩具有什么 编辑:程序博客网 时间:2024/05/16 15:36

故事的起源

起源于在leetcode上面刷题,刷到第39题Combination Sum。
Combination Sum
这道题是一道经典的回溯问题,一个被票选为最佳答案的解决方案如下:

public class Solution {    public List<List<Integer>> combinationSum(int[] nums, int target) {        List<List<Integer>> list = new ArrayList<>();        Arrays.sort(nums);        backtrack(list, new ArrayList<>(), nums, target, 0);        return list;    }    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){        if(remain < 0) return;        else if(remain == 0) list.add(new ArrayList<>(tempList));        else{             for(int i = start; i < nums.length; i++){                tempList.add(nums[i]);                backtrack(list, tempList, nums, remain - nums[i], i); // not i + 1 because we can reuse same elements                tempList.remove(tempList.size() - 1);            }        }    }}

当然还是有更加快速的方法的,请提交后参见More Details里面那个14ms的方法。

我的内心活动

因为我是以前用C++,最近才开始用Java的,当做到这一道题目的时候,我不禁心头一震,要是在整个解空间里不停地调用函数backtrack,是不是所有的参数都要被复制好多好多份,放在内存里,当测试用例特别大的时候,会不会造成很高的空间复杂度?

这时我想起了C++的引用传值大法,这样的话就不会在调用函数的时候把那些参数变量复制一份,大家一起公用一份就可以了,那么我自然而然的想到,Java中的引用参数是怎么玩的?

对Java面向对象理解

然而我的疑惑很快就解开了,大家可以看《Head First Java》这本书的55页到58页。Java中的每一个变量,本质上都是一个“遥控器”。一般声明一个变量比如 tv a; ,表示我买了一个新的遥控器a(注意,前面的tv应该理解成遥控器a是专用来遥控电视的,遥控不了空调等其他设备),a = new tv; 表示家里新买了一台电视,然后我们用我们已经有的遥控器来绑定这台电视。

假如有一天遥控器丢了,或者去遥控其他的电视了,那么Java虚拟机会帮助我们回收这台电视。

回到回溯法上面来

那么,显然我对于回溯问题巨大的解空间树的担心是多余的。因为每一次调用函数backtrack,参数其实都只是遥控器而已,遥控器嘛,能占多大的地方呢?表面看上去是一个参数的复制(C++视角),实际上不过是用两个遥控器遥控同一台电视而已(Java视角),电视一直就只占一份内存,遥控器嘛,多几个又怎么样呢?

我想这大概就是这么多人喜欢Java的原因之一吧。)——来自一个Java菜鸟的无病呻吟。

原创粉丝点击