在Java中通过引用传递和在C中传递指针有什么区别?

时间:2009-03-01 22:16:40

标签: java c pointers pass-by-reference

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

我有点困惑,我的印象是通过引用传递对象并将指针传递给该对象是同样的事情:我认为不同之处在于Java中所有对象的传递都是自动完成的,在C中,人们必须在这里和那里洒上小小的星号和&符号。最近,在谈话中,我确信存在差异!

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

10 个答案:

答案 0 :(得分:39)

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之后将为null。相反,y的值只是一个引用,该引用按值传递。令人困惑的是因为“引用”这个词在两​​个方面都有,但它们是不同的东西。

您可能希望查看my article about C# parameter passing以了解如果Java 具有传递引用语义的可能性,正如C#在您使用时(并且仅在何时)执行ref关键字。

您可能还想查看与该主题相关的my Stack Overflow answer评论。

答案 1 :(得分:7)

  

我认为不同之处在于,在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中的“基本类型”之间没有区别<他们认为。

答案 2 :(得分:3)

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

答案 3 :(得分:2)

一些事情

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

答案 4 :(得分:2)

我相信指针是一个包含引用的变量。 随着&amp;你可以获得一个内存方向(参考),并且*可以访问内存方向的内容。 我建议使用这本书The C programming Language

此致

答案 5 :(得分:2)

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

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

答案 6 :(得分:1)

如果你正在学习C(而不是C ++),那么就没有参考。

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

在许多方面,这与您在Java中看到的类似,除了在Java中您不必将事物显式转换为指针或取消引用它们。换句话说,当您传递指针时,地址将被复制到堆栈中,因此如果您的函数更改了指针(而不是指向的数据),则在完成该功能后,更改将消失。类似地,当您在Java中传递对象引用时,您可以更改对象的内容(例如,通过调用函数),但是一旦离开,将varialbe更改为指向其他对象将不起作用。

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

答案 7 :(得分:1)

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

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

引用文章:

  

指针严格地比参考文献“更强大”;你可以用指针做的任何你可以做的事情。 [...]

     

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

     

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

     

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

     

与引用相比,使用包含地址的指针可以做更多事情。地址可以用数学方法处理;你可以从另一个中减去,你可以为它们添加整数,依此类推。他们的合法操作表明他们是“花哨的数字”,索引到“阵列”,即该过程的虚拟地址空间。

答案 8 :(得分:1)

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

  • java不支持&amp;运算符然后如何在java中获取对象地址。
  • 在java中,引用由对象完成,例如

MyClass object1 = new MyClass();

MyClass object2 = object1;

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

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

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

答案 9 :(得分:0)

我不确定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中将x增加1时调用方法Foo并通过refrence传递x时原始值也会增加

相关问题