【问题标题】:How are arrays passed to a function in JavaJava中如何将数组传递给函数
【发布时间】:2014-10-20 03:23:34
【问题描述】:

在 C 中,当我们在函数调用中传递数组时,仅传递指向该数组的指针以提高内存和时间效率,并且我们无法计算被调用函数中数组的大小。我们必须将大小作为参数传递给被调用的函数。 但是,在 Java 中,我们也可以在被调用函数中计算数组的大小。所以,它不会影响内存效率,因为我想整个数组都被传递给被调用的函数。有人可以详细说明一下吗?

【问题讨论】:

  • 数组是 Java 中的对象。所以引用被传递给方法。
  • 您为什么会假设正在制作副本?如果您使用 C 语言编写并需要这样做,您只需传递长度(就像许多 API 一样)。 Java 在幕后做到了这一点。

标签: java c parameter-passing function-calls


【解决方案1】:

Java 和 C 是完全不同的语言,它们对待数组的方式非常不同;不要假设一个规则适用于另一个。

在Java 中,数组是Object 类的子类,并且继承了该类的所有属性和方法。 Java 数组为数组元素留出了一块连续的内存(至少,我认为它是连续的),但它们也为数组元数据和基本的Object 方法留出了内存。

在 C 中,数组只是 T 类型的元素的连续序列,没有额外的元数据。

C 源自于称为 B 的早期语言;在 B 中,当您声明一个 N 元素数组时,编译器将预留 N+1 个“单元”,其中一个将存储数组开头的偏移量,并且该单元将绑定到标识符;给定声明

auto arr[2];

你会在内存中看到类似的东西:

        +---+        
   arr: |   |-----+
        +---+     |
         ...      |
        +---+     |
arr[0]: |   |<----+
        +---+
arr[1]: |   |
        +---+

Ritchie 最初保留了这个单独的指针变量,但在向语言中添加结构类型时遇到了问题。最终,他完全摆脱了它,所以当你声明一个数组时,你得到的只是:

        +---+     
arr[0]: |   |
        +---+
arr[1]: |   |
        +---+

指向第一个元素的指针没有单独的存储空间;相反,当您在表达式中使用数组名称时会计算指针(也就是说,除非它是一元 &amp;sizeof 运算符的操作数,否则 arr 将计算为数组第一个元素的地址,或&amp;arr[0])1

在 Java 和 C 中,传递给函数的唯一内容是数组的引用 (Java) 或指针 (C),而不是数组本身的副本。


1。因为没有单独的指针变量,arr&amp;arr 都会给你相同的 value (数组的第一个元素的地址与数组的地址相同),但是两个表达式的类型会有所不同;第一个是T *,第二个是T (*)[N]。请注意,在 B 中,&amp;arr 给您与 arr 不同的结果。

【讨论】:

    【解决方案2】:

    在 Java 中(几乎)一切都是指针(更具体地说是引用),而在 C 中一切都是值。

    一个小例子来说明:

    在 C 中:

    struct MyStruct {
        int  myInt;
        bool myBool;
    };
    MyStruct a = { .myInt = 5, .myBool = true};
    //following line will cause a CLONE of a to be put in b.
    MyStruct b = a;
    

    上面的代码声明了一个结构,初始化它并克隆该结构到另一个结构(意思是值被复制而不是引用,即改变一个不会改变另一个)。

    在 java 中声明 b = a 仅复制引用(即更改 a.myInt 也会更改 b.myInt),为了在 C 中实现类似的功能,我们将编写让 b 成为指向 MyStruct 的指针并声明b = &amp;a

    因此,在向 java 中的方法传递参数时,我们实际上是在传递对该对象的引用(除非我们使用原始类型,例如 int、bool、char 等)。 Java 数组方便地预先打包了它们的大小(在 C 中,我们可以只创建一个数组结构和一个 int 作为它的长度)。

    【讨论】:

      【解决方案3】:

      数组是按值传递的,其中值是数组的内存地址。

      另外,请在此处阅读我的详细回复State of an ArrayList in a recursive method

      【讨论】:

      • 您可能会争辩说,Java 中的一切都是按值传递的。由于 Object 只是指针,因此它们的值被复制到被调用函数或在返回时复制。
      • 是的,你可以。 java中的对象是指向内存中某个位置的指针。这些是按值传递的。当你在 java 中声明 'Object obj' 时。您不是在声明一个对象,而是在声明一个指针或对内存位置的引用。提示访问空对象时遇到的 NullPointerException。
      • 我看不出这与我所说的有什么不同。 Java Object 变量只是指向实际 Object 的指针/引用,这些指针/引用是按值复制的。
      • 它们是 C 意义上的指针。您将它们与指向指针的指针混淆了。当您在 Java 中声明“Object obj”时,您基本上是在 C 中声明“Object *obj”。您不是在声明“Object **obj”,您可以在其中编辑被调用函数中的指针。有很大的不同。
      • 您指向我的所有内容都与我所说的完全相同。对象引用是按值传递的,因为它们只是指针。 pastebin.com/LBe5iSt2 和它等效的 C++ 代码 pastebin.com/iX17uCtS
      【解决方案4】:

      这里的区别在于Java中的数组是知道自己大小的对象。我们仍然在传递对数组的引用,只是被引用的内存具有 C 中未携带的信息。

      【讨论】:

        【解决方案5】:

        java中的数组是一个对象,包含数组的元素和大小。

        当你传递一个数组时,只传递对数组对象的引用——该数组不会被复制,并且在方法中对数组所做的任何更改都会反映到调用环境中。

        【讨论】:

        • 好的..所以数组对象有一个成员元素代表它的大小?
        • @user3126841 yourArray.lengthlength 字段表示数组的大小。
        • @user3126841 只需将 Array 视为一种 Object 类型,具有“public final int length”和“length”其他成员,这些成员通过 [] 运算符间接寻址。除此之外,它们遵循适用于其他对象的相同基本思想。虽然 Java 字节码没有说 Array 对象有一个 'length' 成员,而是由 'arraylength' 操作码访问。
        • 非常感谢大家..我现在明白了 :-)
        猜你喜欢
        • 2016-04-09
        • 1970-01-01
        • 2012-07-23
        • 2017-06-03
        • 2019-09-24
        • 2011-12-26
        • 1970-01-01
        相关资源
        最近更新 更多