2009-03-01 118 views
15

我一直在学习Java的几个月,我现在开始学习C.在Java中传递引用和在C中传递指针有什么区别?

我有点困惑,我的印象是,通过引用传递对象和指针传递到该对象是相同的事情:我认为不同的是,在Java中,所有对象的传递都是自动完成指针的,在C中,实际上在这里和那里实际上要洒上星号和&符号。最近,在谈话中,我确信有一个区别!

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

回答

39

Java既不是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#做时(且仅当)您使用ref关键字。

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

3

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

1

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

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

在许多方面,这与您在Java中看到的类似,只不过在Java中您不必将事物明确地转换为指针或对其进行解引用。换句话说,当你传递一个指针时,地址被复制到堆栈中,所以如果你的函数改变指针(而不是指向它的数据),当你完成这个函数时,这些改变就会消失。同样,当您在Java中传递对象引用时,可以更改对象的内容(例如,通过调用函数),但是如果将变量指向anothr对象,则离开后无效。

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

+0

嘿,可以这样说:“指针”是一种数据类型,“引用”只是一种处理数据的方式?一个是事物,另一个是技术? *我试图避免在这里使用“方法”的不明确性 – Ziggy 2009-03-01 22:33:25

+0

指针肯定是一种数据类型。然而,在C++(大多数C人最终使用)中,有一种称为参考的数据类型。这是一个问题,因为在C++中实际上有两种“通过引用传递”的方式,通过实际引用和通过指针。所以“通过参考”是一种方法。 – Uri 2009-03-01 23:14:55

2

有几件事情

  • C没有引用(尽管C++的)
  • Java没有指针
  • 指针和引用的区别是,指针实际上是内存地址,你可以计算用。参考文献不能被数值与
  • Java和C通计算(当传递在Java中的对象时,参考被复制到功能)
+0

我建议你从最后一个项目符号中删除“默认”一词 - C和Java按值传递,故事结束。 – 2009-03-01 22:32:30

2

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

问候

1

Eric Lippert最近有一篇关于这方面的文章。他对C#编译器的程序员,但无论他说,有有足够的普遍性扩展到其他GC语言如Java:从文章

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

报价:

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

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

由于所有这些原因,我们没有在说明书中将引用描述为地址。该规范只是说,引用类型的变量“存储引用”给一个对象,并且对于如何实现这个对象而言完全模糊不清。同样,一个指针变量存储一个对象的“地址”,这个对象仍然很模糊。我们没有任何地方说参考地址与地址相同。

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

与引用相比,您可以使用包含地址的指针做更多的事情。地址可以通过数学操作;你可以从另一个中减去一个,你可以为它们添加整数,等等。他们的合法操作表明他们是“幻想号码”,它们将索引到“阵列”中,即“虚拟地址空间”。

+0

这是在谈论引用而不是“通过参考” - 它们是相关但不同的概念。 – 2009-03-01 22:31:01

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中的“原始类型”在中没有区别那方面。

0

林不知道有关Java,但在C#或VB.net,你可以通过值或refrence

例如路过refrence

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和x通过引用传递x原始值也增加

1

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

  • java不支持&运算符然后如何获得java中的对象地址。
  • 在java中参考由对象例如)进行

MyClass的object1 =新MyClass的(;

MyClass object2 = object1;

即你可能认为object1和object2引用单独和不同的对象。 但是,这将是错误的。相反,在执行此片段后,object1和object2都将引用同一个对象。如果你改变其他任何一种效果。你可以在初始化后不改变对象的地址 即MyClass obj = new MyClass(); 作为C++的参考,带对象只能改变对象实例的值

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