【问题标题】:What is the difference between passing by reference in Java and passing a pointer in C?在 Java 中通过引用传递和在 C 中传递指针有什么区别?
【发布时间】:2010-10-10 16:22:08
【问题描述】:

我已经学习 Java 几个月了,现在开始学习 C。

我有点困惑,我的印象是通过引用传递对象和传递指向该对象的指针是一回事:我认为不同之处在于,在 Java 中,所有对象的传递都是通过指针自动完成的,就像在 C 中一样,实际上必须在这里和那里撒上小星号和 & 符号。最近,在谈话中,我确信这是有区别的!

引用传递和指针传递有什么区别?

【问题讨论】:

    标签: java c pointers pass-by-reference


    【解决方案1】:

    熟悉 C/C++ 的读者可能已经注意到对象引用的出现 类似于指针。这种怀疑基本上是正确的。对象引用是 类似于内存指针。主要区别——也是 Java 安全的关键——是 您不能像操作实际指针一样操作引用。因此,您不能导致 指向任意内存位置或像整数一样操作它的对象引用。

    • java 不支持 & 运算符,那么如何在 java 中获取对象地址。
    • 在 java 中引用是由对象完成的,例如

    MyClass object1 = new MyClass();

    MyClass object2 = object1;

    即您可能会认为 object1 和 object2 指的是独立且不同的对象。 然而,这是错误的。相反,在这个片段执行之后,object1 和 object2 都将引用同一个对象。如果你改变任何一种效果。

    *初始化后不能更改对象的地址 即 MyClass obj =new MyClass(); 作为 c++ 中的参考,使用对象只能更改对象实例值

    注意:java提供了一个特殊的功能 object1 已设置为 null,但 object2 仍指向原始对象。

    【讨论】:

      【解决方案2】:

      我不确定 java,但在 C# 或 VB.net 中,您可以按值或通过引用传递

      引用传递的例子

          static void Main(string[] args)
          {
              int x = 1;
              Foo(ref x);
              Console.WriteLine(x.ToString());//this will print 2
          }
      
          private static void Foo(ref int x)
          {
              x++;
          }
      

      请注意 x 等于 1,但是当您调用方法 Foo 并在 Foo 中 x 增加 1 时通过引用传递 x 时,原始值也会增加

      【讨论】:

        【解决方案3】:

        我认为不同之处在于,在 Java 中,所有对象的传递都是通过指针自动完成的,而在 C 中,实际上必须在各处添加小星号和与号。

        概念,这是完全正确的。如果我们是迂腐的(这是一件好事),我们甚至可以说在 Java 中根本不传递对象。传递的只是“指针”,在 Java 中称为引用。所有间接都是自动完成的。因此,当您在 C 中执行“objref->foo”而不是“objref.foo”并且由于使用指针而不能使用点时,在 Java 中您仍然可以使用点,因为它不知道任何其他内容无论如何访问成员。在 C 中,您可以传递指针(这里,它实际上称为指针)并且您可以传递对象本身,在这种情况下传递一个副本。在 C 中,您可以使用星号或“->”间接访问指针所引用的对象。在 Java 中,访问对象的唯一方法是使用点 (objref.member)。

        如果我们又学究气了(现在又变得更重要了),那么在 Java 和 C 中都没有“通过引用传递”。我们在 Java 中传递的是对象的引用/指针,而在 C 中,我们要么传递对象的副本(很明显),要么再次传递指向对象的指针的副本。所以在这两种情况下——Java 和 C——我们传递的是对象的地址。不谈论在 Java 和 C 中复制的原始 java 类型 - 即使您也可以在 C 中传递它们的地址,聚合类型(即结构)和 C 中的“原始类型”之间没有区别 那个方面。

        【讨论】:

          【解决方案4】:

          一些事情

          • C 没有引用(尽管有 C++)
          • Java 没有指针
          • 指针和引用之间的区别在于,指针实际上是可以用来计算的内存地址。无法计算参考文献
          • Java和C按值传递(在Java中传递对象时,引用被复制到函数中)

          【讨论】:

          • 我建议您从最后一个项目符号中删除“默认情况下”这个词 - C 和 Java 通过值传递,故事结束。
          【解决方案5】:

          Java C 都没有传递引用。它们都是严格按值传递的。

          按引用传递语义意味着当您更改方法中参数的值时,调用者将看到参数中的更改。

          现在,您可能会想:“但在 Java 中就是这种情况!如果我在方法期间更改对象,调用者会看到该更改。” 对象不是参数。参数是只是变量——如果你改变那个变量的值,调用者不会看到。例如:

          public void foo(Object x)
          {
              x = null;
          }
          
          public void caller()
          {
              Object y = new Object();
              foo(y);
              // y is still not null!
          }
          

          如果参数真的通过引用传递,y 之后将为空。相反,y 的值只是一个引用,并且该引用是按值传递的。这很令人困惑,因为“参考”一词在这两个术语中都有,但它们是不同的东西。

          您可能想查看my article about C# parameter passing 以了解如果Java 确实 具有传递引用语义会发生什么,就像C# 在(且仅当)您使用@987654326 时所做的那样@关键字。

          您可能还想查看与该主题相关的 cmets 至 my Stack Overflow answer

          【讨论】:

          • 非常非常真实。这是我见过的编程中最容易被误解的方面之一。
          • 是的,按值传递的引用是 C# 中最让我感到困惑的事情之一
          • 这显示了 Joel (The Joel) 对人的评价——他们要么摸索指针,要么不摸索。要了解指针,您必须能够区分“参考”和其他参考 =)
          • 为什么说C不能通过引用传递? C 和 C++ 都可以。对于 C:void foo(Type * val),调用者是 foo(&y)。此调用将修改 y 的值。对于 C++: void foo(Type & val) 调用者只是 foo(y)
          • @Max:不,在foo(&y) 的情况下,参数的值被传递。论据是什么? &y。该表达式采用y 的地址,然后按值传递结果。 C++ 确实有传递引用,但 C 真的没有。
          【解决方案6】:

          Eric Lippert 最近有一篇关于此的文章。他是 C# 编译器的程序员,但无论他说什么,都具有足够的通用性,可以扩展到其他 GC 语言,例如 Java:

          http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx

          引用文章:

          指针严格来说比引用“更强大”;你可以用引用做任何事情,你可以用指针做任何事情。 [...]

          指针通常实现为地址。地址是一个数字,它是“字节数组”的偏移量,“字节数组”是进程的整个虚拟地址空间。 [...]

          出于所有这些原因,我们在规范中没有将引用描述为地址。规范只是说引用类型的变量“存储了对对象的引用”,并且对于如何实现它完全模糊。类似地,指针变量存储对象的“地址”,这又是非常模糊的。我们没有说引用与地址相同。

          因此,在 C# 中,引用是一些模糊的东西,可以让您引用一个对象。除了取消引用之外,您不能对引用做任何事情,并将其与另一个引用进行比较以获得相等性。而在 C# 中,指针被标识为地址。

          与引用相比,使用包含地址的指针可以做更多事情。地址可以用数学方法进行操作;您可以从另一个中减去一个,您可以向它们添加整数,等等。它们的合法操作表明它们是“花哨的数字”,索引到作为进程虚拟地址空间的“数组”中。

          【讨论】:

          • 这是在谈论引用而不是“通过引用”——它们是相关但不同的概念。
          【解决方案7】:

          True pass-by-reference 意味着您可以为引用分配一个新值,并且这个新值将在调用上下文中可见,就像在被调用方法内部一样。

          在 Java 中,这是不可能的,因为object references are passed by value

          【讨论】:

            【解决方案8】:

            我相信指针是一个包含引用的变量。 使用 & 可以获得内存方向(参考),使用 * 可以获得内存方向的内容。 我推荐这本书The C programming Language

            问候

            【讨论】:

              【解决方案9】:

              如果您正在学习 C(而不是 C++),则没有参考资料。

              C 中的术语“按引用传递”仅表示您将指针作为存储值的地址传递,以便函数可以更改其值。 否则,您将按值传递,这意味着在堆栈上生成变量的副本并且修改没有影响。

              在许多方面,这与您在 Java 中看到的相似,只是在 Java 中您不必显式地将事物转换为指针或取消引用它们。换句话说,当你传递一个指针时,地址被复制到堆栈上,所以如果你的函数改变了指针(而不是它指向的数据),当你完成函数时,改变就会消失。同样,当您在 Java 中传递对象引用时,您可以更改对象的内容(例如,通过调用函数),但是一旦您离开,将变量更改为指向另一个对象将没有任何效果。

              如果你使用的是C++(看起来像C),那么你可以通过引用传递,在这种情况下你不需要处理指针,而函数中变量的改变实际上直接改变了外部值(除了你不能让它指向别的东西)。

              【讨论】:

              • 咦,难道说:“指针”是一种数据类型,而“引用”只是一种处理数据的方式*?一个是东西,另一个是技术? * 我试图避免在这里使用“方法”的歧义
              • 指针肯定是一种数据类型。但是,在 C++(大多数 C 人最终使用)中,有一种称为引用的数据类型。这是一个问题,因为在 C++ 中实际上有两种“通过引用传递”的方式,通过实际引用和通过指针。所以“通过引用”是一种方式。
              【解决方案10】:

              差异是微妙的。在汇编级别,在这两种情况下,对象的地址都被传递给函数。但是,在指针的情况下,参数是一个独立的指针,可用于修改目标对象 (*pch = 'x') 或可用于访问不同的对象 (pch = "newstr")。在引用情况下,参数会自动间接到目标对象。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-09-24
                • 2020-03-14
                • 2012-03-03
                • 2020-05-14
                • 1970-01-01
                • 2012-11-19
                • 2015-08-27
                • 1970-01-01
                相关资源
                最近更新 更多