Java:数组为什么不是引用传递的?

douya0808
  • 429

LeetCode 第 189 题要求将数组 nums 中元素均向右移动 k 位

public class Solution {
    public static void main(String[] args) {
        int[] nums = { 1, 2, 3, 4, 5, 6, 7 };
        new Solution().rotate(nums, 3);
    }
    public void rotate(int[] nums, int k) {
        int[] ret = new int[nums.length];
        for (int i = 0; i <= nums.length - 1; i++) {
            ret[(i + k) % nums.length] = nums[i];
        }
        System.arraycopy(ret, 0, nums, 0, nums.length); // 正确
        // nums = array; // 错误
    }
}

我的疑问是为什么最后的步骤需要通过 System.arraycopy 复制数组元素,而不能直接写成 nums = array 呢?我直接将 nums 这个引用指向 array 的内存地址不可以吗?求解


看完《深入理解Java虚拟机》回来复盘这个问题,其实不用理解与区分值传递引用传递的概念与二者在Java与C++的区别,理解Java虚拟机的运行时数据区即可,罗列几点对我自己理解这个问题的知识点:

  • 数组普通对象没有区别,只是数组中会存储附加字段记录当前数组长度而已,所以数组普通对象都是存储在中的
  • 不同方法会对应不同的栈帧栈帧中有私有的局部变量表用于存储当前方法涉及到的变量,main 方法中的 nums 已预先添加至 main 方法的栈帧局部变量表,main 方法调用 rotate 方法时,形参会添加至 rotate 方法的栈帧局部变量表,也就是说目前全局会有两个 nums 引用,分别存储在 main 方法的局部变量表与 rotate 方法的局部变量表,互相独立,因此将 rotate 方法中的 nums 指向 ret 时,main 方法中的 nums 并不受影响
  • Java虚拟机中的数据类型除了我们常见的boolean、byte、char、short,还有一种叫做reference,也就是我们通常理解的引用

    原本写了很多图文讲解的,突然SegmentFault崩溃了网页突然全灰什么都没了MLGB,仍有问题的推荐阅读《深入理解Java虚拟机》或者给我留言,我们一起讨论
回复
阅读 1.4k
5 个回答
✓ 已被采纳

我原来也碰到过这种问题,我的理解方式是:在调用方法的时候,将参数引用放入了调用方法的栈帧中,这个栈帧和main方法的栈帧不是同一个栈帧,有自己的局部变量表,所以无论如何也影响不了main的局部变量表,是无法修改的。但这个引用指向堆,而堆是共享的,所有可以修改这个对象的属性。不过我好像在哪里看见过局部变量表也可以部分共享,我不知道是哪部分,但应该没有包含参数引用,否则可能乱套,欢迎指正和补充。

#include <vector>
using namespace std;

vector<int> newNums = { 0 };
void rotate(vector<int>* nums) {

    //错误: 改变了nums指针的指向,但是原来他指向的对象什么都没改变还是原来的值
    nums = &newNums;

    //正确:改变nums指针指向对象的内容
    *nums = newNums;
}

int main() {
    vector<int> vec = { 1 };
    vector<int>* nums = &vec;
    rotate(nums);
    cout << (*nums)[0] << endl;
}

同理,如果直接给nums赋值也只是修改了nums指针的指向并没有对原来的nums做更改,而arraycopy则是把新的值写道nums指向的对象里

菜鸡的一点点看法,Java中方法参数的传递是值传递而不是引用传递,也就是说参数中的nums只是一个副本,原nums和副本nums并不是同一个对象引用,所以方法内最后进行赋值的时候需要使用arraycopy()方法。

double money1=10;
doubleMoney(moeny1);
public static void doubleMoney(double money){
money=money*2;
}

money1的值不会改变。
return int[] ...方法可能更好

Java 中的引用传递和 C++ 中的引用传递不同。

C++ 中的引用相当于是指针的地址,可以回写。

Java 的引用相当于指针,你可以改变指向的对象,但不能改变实参引用。如果把引用理解成一个 int 型(或者 long,无所谓了)的地址值,参数传递的是这个值,大概应该就能理解了吧。

nums = array 只是改变了 rotate 函数内的 局部变量的值。改变不了 main函数里的nums。

宣传栏