メソッド呼び出し (call by) は標準的なコンピューター サイエンス用語です。メソッド呼び出しは、渡されるパラメーターに応じて、値呼び出し (参照による呼び出し) と参照呼び出し (値による呼び出し) に分けられます。これら 2 種類の呼び出しについては、世の中にたくさんの定義があります。最も一般的なのは、値を渡すものは値呼び出し、アドレスを渡すものは参照呼び出しであるということです。これは実際には非常に不適切です。これらの記述は、Java のオブジェクト パラメータの受け渡しが参照呼び出しであることを容易に思い出させます。
まず、コードの一部を使用して、Java のオブジェクト パラメーターの受け渡しが値によって呼び出される理由を検証してみましょう。
public class Employee { public String name=null; public Employee(String n){ this.name=n; } //将两个Employee对象交换 public static void swap(Employee e1,Employee e2){ Employee temp=e1; e1=e2; e2=temp; System.out.println(e1.name+" "+e2.name); //打印结果:李四 张三 } //主函数 public static void main(String[] args) { Employee worker=new Employee("张三"); Employee manager=new Employee("李四"); swap(worker,manager); System.out.println(worker.name+" "+manager.name); //打印结果仍然是: 张三 李四 } }
上記の結果は非常に残念です。仮パラメータオブジェクト e1 と e2 の内容は交換されますが、実パラメータオブジェクト worker と manager の内容は交換されません。ここでの最も重要な理由は、仮パラメータ e1 と e2 が実際のパラメータ worker と manager のアドレス コピーであるということです。
Java では、オブジェクト変数名が実際にはヒープ内のオブジェクトのアドレスを表すことは誰もが知っています (専門用語はオブジェクト参照と呼ばれます)。 Java メソッドが呼び出されるとき、渡されるパラメータはオブジェクトへの参照です。重要なことは、仮パラメータと実パラメータが占有するメモリ アドレスは同じではないということです。仮パラメータの内容は、実パラメータに格納されているオブジェクト参照の単なるコピーです。
JVM メモリ管理における Java スタックのローカル変数領域 (「Java 仮想マシン アーキテクチャ」を参照) についてある程度の知識がある場合、上記の文は簡単に理解できます。 JVM が上記のプログラムを実行するとき、main メソッドと swap メソッドを実行すると、スタック フレームと呼ばれる 2 つのメモリ空間が Java スタックにプッシュされます。メイン スタック フレームにはローカル変数領域と呼ばれるメモリがあり、実際のパラメータ オブジェクトのワーカーおよびマネージャーへの参照を保存します。スワップ スタック フレームのローカル変数領域には、仮パラメータ オブジェクト e1 および e2 への参照が格納されます。 e1、e2の基準値はそれぞれワーカー、マネージャーの基準値と同じですが、占有するメモリ空間が異なります。 e1 と e2 の参照を交換すると、ワーカーとマネージャーの参照値はまったく影響を受けないことが下の図から明らかです。
Java オブジェクトのパラメータの受け渡しはアドレス (参照) を渡しますが、それでも値の呼び出しです。参照による呼び出しと値による呼び出しを正確に定義する時期が来ました。
値による呼び出し: パラメータの受け渡しプロセス中、仮パラメータと実パラメータは 2 つのまったく異なるメモリ空間を占有します。仮パラメータに格納される内容は、実パラメータに格納される内容のコピーです。実際、Java オブジェクトの転送は、仮パラメータおよび実パラメータに格納される内容が従来の意味での変数値ではなく、変数のアドレスであることを除いて、この定義に準拠しています。咳き込んで、よく考えてみてください。変数のアドレスも値ではないでしょうか?
参照による呼び出し: パラメータ転送のプロセスでは、仮パラメータと実パラメータは完全に同じメモリ空間にあり、互いに分離されません。 実際、正式なパラメータ名と実際のパラメータ名は、プログラミングにおける単なる別の記号です。プログラムの実行中、メモリ内の記憶領域が最も重要です。変数名が異なっても、占有されるメモリ記憶領域が異なるわけではありません。
一般に、2 つの呼び出しの根本的な違いは、値が渡されるかアドレスが渡されるかではなく (結局のところ、アドレスも値です)、仮パラメータと実パラメータが同じメモリ空間を占有するかどうかです。実際、C/C++ で渡すポインター パラメーターも値呼び出しです。信じられない場合は、次の C コードを試してください。
#include<stdio.h> void swap(int *a1,int *b1){ int *t=a1; a1=b1; b1=t; } int main(){ int x1=100; int x2=200; int *a=&x1; int *b=&x2; printf("%d %d\n",*a,*b); swap(a,b); printf("%d %d\n",*a,*b); return 0; }
しかし、これは C/C++ で参照と呼ばれる変数宣言メソッドです: int a; int &ra=a; どちらもメモリ内にはありません。違いは、同じメモリ空間を占有することです。パラメータの参照渡し (エイリアス) は、参照呼び出しの特性に従います。 void swap(int &a1,int &b1); の演算結果を試してみます。
この記事を通じて、Java メソッドのパラメータが参照によって呼び出されるのか、値によって呼び出されるのかを理解する必要があります。
Java メソッドのパラメーターが参照呼び出しであるか値呼び出しであるかに関するその他の記事については、PHP 中国語 Web サイトに注目してください。