私はJavaを数か月勉強していて、今はCを学び始めています。
私は少し混乱しています。参照によってオブジェクトを渡すことと、そのオブジェクトへのポインターを渡すことは同じことであるという印象を受けました。違いは、Javaでは、オブジェクトのすべての受け渡しがポインターを使用して自動的に行われることです。 C 1つは、実際にあちこちに小さなアスタリスクとアンパサンドを振りかける必要があります。最近の会話で、違いがあると確信しました!
参照による受け渡しとポインタによる受け渡しの違いは何ですか?
私はJavaを数か月勉強していて、今はCを学び始めています。
私は少し混乱しています。参照によってオブジェクトを渡すことと、そのオブジェクトへのポインターを渡すことは同じことであるという印象を受けました。違いは、Javaでは、オブジェクトのすべての受け渡しがポインターを使用して自動的に行われることです。 C 1つは、実際にあちこちに小さなアスタリスクとアンパサンドを振りかける必要があります。最近の会話で、違いがあると確信しました!
参照による受け渡しとポインタによる受け渡しの違いは何ですか?
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は単なる参照であり、その参照は値によって渡されます。「参照」という言葉は両方の用語であるため混乱しますが、それらは異なるものです。
C#がキーワードを使用する場合(および使用する場合のみ)のように、Javaに参照渡しのセマンティクスがあった場合に何が可能になるかを確認するには、C#パラメーターの受け渡しに関する私の記事を参照してください。ref
また、トピックに関連するStackOverflowの回答へのコメントもご覧ください。
違いは、Java ではすべてのオブジェクトの受け渡しがポインターを使用して自動的に行われるのに対し、C ではあちこちに小さなアスタリスクとアンパサンドを実際に振りかける必要があることだと思いました。
概念的な、それはまったく正しいです。私たちが衒学的であれば (それは良いことです)、オブジェクトは Java ではまったく渡されないとさえ言えます。渡されるのは、Java では参照と呼ばれる「ポインタ」だけです。すべての間接化は自動的に行われます。したがって、C で "objref.foo" の代わりに "objref->foo" を実行し、ポインターを操作するためにドットを使用できない場合でも、Java ではドットを使用できます。とにかくメンバーにアクセスします。C では、ポインターを渡すことができ (ここでは、実際にはポインターと呼ばれます) 、オブジェクト自体を渡すことができます。この場合、コピーが渡されます。C では、アスタリスクまたは "->" を使用して間接的にポインターが参照するオブジェクトにアクセスします。ジャワでは、
再び衒学的に考えると (今はさらに重要です)、Java にも C にも「参照渡し」はありません。Java で渡すのはオブジェクトへの参照/ポインターであり、C ではオブジェクトのコピーを渡すか (明らかなケース)、オブジェクトへのポインターのコピーだけを渡します。したがって、Java と C のどちらの場合でも、渡すのはオブジェクトのアドレスです。Java と C の両方でコピーされる Java のプリミティブ型については話していません。C でもアドレスを渡すことができますが、集約型 (構造体) と C の「プリミティブ型」の間に違いはありません。由来。
違いは微妙です。アセンブリレベルでは、どちらの場合も、オブジェクトのアドレスが関数に渡されます。ただし、ポインターの場合、パラメーターは、ターゲットオブジェクトを変更するために使用できる(* pch ='x')、または別のオブジェクトにアクセスするために使用できる(pch = "newstr")独立したポインターです。リファレンスケースでは、パラメータは自動的にターゲットオブジェクトにリダイレクトされます。
いくつかのこと
ポインタは参照を含む変数だと思います。&を使用すると、メモリ方向(参照)を取得できます。*を使用すると、メモリ方向のコンテンツにアクセスできます。私は本Cプログラミング言語を提案します。
よろしく
真の参照渡しとは、参照に新しい値を割り当てることができることを意味します。この新しい値は、呼び出されたメソッド内と同じように、呼び出し元のコンテキストに表示されます。
Javaでは、オブジェクト参照は値によって渡されるため、これは不可能です。
(C ++ではなく)Cを勉強している場合、参照はありません。
Cでの「参照渡し」という用語は、関数がその値を変更できるように、値が格納されるアドレスとしてポインターを渡すことを意味します。それ以外の場合は、値を渡すことになります。つまり、変数のコピーがスタックに生成され、変更による影響はありません。
多くの点で、これはJavaで見られるものと似ていますが、Javaでは、物事を明示的にポインターに変換したり、逆参照したりする必要がない点が異なります。つまり、ポインターを渡すと、アドレスがスタックにコピーされるため、関数が(ポインターが指すデータではなく)ポインターを変更すると、関数を終了したときに変更が消えます。同様に、Javaでオブジェクト参照を渡す場合、オブジェクトの内容を変更できます(たとえば、関数を呼び出すことによって)が、他のオブジェクトを指すようにvarialbeを変更しても、離れると効果はありません。
C ++(Cのように見える)を使用している場合は、参照で渡すことができます。その場合、ポインターを処理する必要はなく、関数内の変数を変更すると、実際には外部値が直接変更されます(ただし、他の何かを指すようにすることはできません)。
これについてのEricLippertによる最近の記事があります。彼はC#コンパイラーのプログラマーですが、Javaなどの他のGC言語に拡張するのに十分な一般性があると彼は言っています。
http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx
記事からの引用:
ポインタは、参照よりも厳密に「強力」です。ポインタを使ってできることはすべて、参照を使ってできることです。[...]
ポインタは通常、アドレスとして実装されます。アドレスは、プロセスの仮想アドレス空間全体である「バイトの配列」へのオフセットである数値です。[...]
これらすべての理由から、仕様では参照をアドレスとして説明していません。仕様では、参照型の変数がオブジェクトへの「参照を格納する」と述べているだけであり、それをどのように実装するかについては完全にあいまいなままです。同様に、ポインタ変数はオブジェクトの「アドレス」を格納しますが、これもかなりあいまいなままです。参照がアドレスと同じであるとはどこにも言いません。
したがって、C#では、参照はオブジェクトを参照できる漠然としたものです。参照を逆参照し、それを別の参照と比較して同等である以外は、参照に対して何もできません。また、C#では、ポインターはアドレスとして識別されます。
参照とは対照的に、アドレスを含むポインターを使用すると、さらに多くのことができます。アドレスは数学的に操作できます。互いに減算したり、整数を加算したりすることができます。それらの法的な操作は、それらがプロセスの仮想アドレス空間である「配列」にインデックスを付ける「ファンシーナンバー」であることを示しています。
C / C ++に精通している読者は、オブジェクト参照がポインターに似ているように見えることにおそらく気づいたでしょう。この疑惑は、本質的に正しいものです。オブジェクト参照は、メモリポインタに似ています。主な違い(およびJavaの安全性の鍵)は、実際のポインターとは異なり、参照を操作できないことです。したがって、オブジェクト参照が任意のメモリ位置を指すようにしたり、整数のように操作したりすることはできません。
MyClass object1 = new MyClass();
MyClass object2 = object1;
つまり、object1とobject2は別々の別個のオブジェクトを参照していると思うかもしれません。ただし、これは間違っています。代わりに、このフラグメントが実行された後、object1とobject2は両方とも同じオブジェクトを参照します。いずれかの効果を他の効果に変更した場合。
*初期化後にオブジェクトのアドレスを変更することはできません。つまり、MyClass obj = new MyClass(); c ++での参照として、オブジェクトではオブジェクトインスタンス値のみを変更できます
注:javaは特別な機能を提供しますobject1はnullに設定されていますが、object2は元のオブジェクトを指しています。
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 を渡すと、Foo で x が 1 増加すると、元の値も増加します。