特定のコンピュータプログラミング言語では、データ型は値型または参照型に分類されます。参照型変数によって参照される値は、常にそれらの変数に格納されている参照を介して暗黙的にアクセスされますが、値型変数は値自体を直接保持します。[ 1 ] [ 2 ]
このような区別を持つ言語であっても、値型と参照型の具体的な特性は言語によって異なりますが、典型的な特性としては以下のようなものがあります。
intInteger関数引数が「値渡し」セマンティクスを使用して渡される場合(Javaでは常にそうであり、C#ではデフォルトでそうである)、参照型の値は本質的に参照です。したがって、パラメーターが参照型に属している場合、結果として生じる動作は「参照渡し」セマンティクスにいくらか似ています。この動作は「共有渡し」と呼ばれることもあります。
共有呼び出しは、関数が引数として受け取ったオブジェクトを変更する場合、参照呼び出しと似ています。この場合、呼び出し元と関数は同じオブジェクトへの参照を持っているため、変更は呼び出し元にも反映されます。一方、関数がパラメータを別の参照に代入する場合、参照呼び出しとは異なります。この場合、呼び出し元と関数はそれぞれ別の参照を持っているため、たとえ両方の参照が最初は同じオブジェクトを指していても、代入は呼び出し元には反映されません。
多くの言語には明示的なポインタや参照があります。参照型は、参照先のエンティティに常に参照を介してアクセスするという点で、これらとは異なります。たとえば、C++ では、可変文字列である と可変文字列への明示的なポインタ ( null ポインタでない限り) の両方を持つことができますが、Java では、可変文字列への暗黙的な参照 (null 参照でない限り) である しか持つことができません。std::stringstd::string*StringBuilder
C++のアプローチはより柔軟ですが、非参照を使用すると、少なくとも継承を使用する場合は、オブジェクトのスライスなどの問題が発生する可能性があります。オブジェクトが参照型に属する言語では、プログラマーの選択肢が一部制限されるという代償を伴いますが、これらの問題は自動的に回避されます。
ほとんどのプログラミング言語では、参照型の変数を別のオブジェクトを参照するように変更する、つまり変数を別のオブジェクトに再バインドすることが可能です。
例えば、以下のJavaコードでは:
class Foo { public int a ; }Foo a = new Foo ( ) ; Foo b = a ; a.prop = 3 ; a = new Foo ( ) ; a.prop = 1 ;Fooは参照型であり、aは最初に新しいオブジェクトの参照が割り当てられ、bは同じオブジェクト参照、aつまり と同じオブジェクトにバインドされているため、 は を通じて変化し、aも から参照できますb。その後、aは別の新しいオブジェクトへの参照(再バインド)が割り当てられ、 と はa異なるbオブジェクトを参照するようになります。最終的に、は のフィールドの値が であるa2 番目のオブジェクトを参照し、は のフィールドの値が である最初のオブジェクトを参照します。prop1bprop3
しかし、C++などの言語では、「参照型」という用語はエイリアスを意味するために使用され、参照型の変数は元のオブジェクトへのエイリアスであるため、一度作成されると再バインドすることはできません。
class Foo { public : int a ; };Foo a ; a . prop = 1 ; Foo & b = a ; Foo c = a ; a . prop = 3 ;C++ では、参照型以外のすべてのクラス型は値セマンティクスを持ちます。上記の例では、bはの参照 (エイリアス) として宣言されておりa、あらゆる点で、aとはb同じものです。をb別のものに再バインドすることはできません。上記の例を実行すると、aとはb同じFooオブジェクトになり、propはがになります。一方、は元ののコピーで、はになります。3caprop1
C# では、値型と参照型の区別とは別に、参照変数と呼ばれる別の概念もあります。[ 3 ]参照変数は、宣言およびバインドされると、元の変数のエイリアスとして動作しますが、参照代入演算子を使用して別の変数に再バインドすることもできます= ref。変数自体は、値型や参照型を含む任意の型にすることができます。つまり、参照型の変数を参照 (エイリアス) で関数に渡すと、参照型の変数が指すオブジェクト自体 (可変の場合) に加えて、そのオブジェクトも変更できます。
オブジェクトが不変であり、オブジェクトの等価性が同一性ではなく内容に基づいてテストされる場合、値型と参照型の区別はもはや明確ではありません。なぜなら、オブジェクト自体は変更できず、全体として置き換える(値型の場合)か、別のオブジェクトを指す参照に置き換える(参照型の場合)ことしかできないからです。このような不変オブジェクトを変数間で渡す場合、オブジェクトの同一性が取得されない限り、オブジェクトがコピーされるか参照渡しされるかで、目に見える違いはありません。Haskellのような、何も変更できない関数型プログラミング言語では、このような区別は全く存在せず、実装の詳細となります。