この記事を読む前に、あなた自身の経験と理解に基づいて、まず Java 関数のパラメータ受け渡し方法について考えて選択してください。
A. 値渡しですか?
B. 参照によって渡されましたか?
C. 部分的には値によるもので、部分的には参照によるものですか?
正解はまだここでは発表されません。簡単な例を通して、自分で答えを見つけてください。
1. 最初に型値を定義します
public static クラス Value { private String value = "value"; public String getValue() { return value; } public void setValue(String value) { this.value = value; }
2. 2 つの関数 newValue と modifyValue を作成します。newValue は入力パラメータが新しいオブジェクトを指し、modifyValue は入力パラメータの setValue メソッドを呼び出してオブジェクトの値を変更します。
public static void newValue(Value value) { value = new Value(); value.setValue("新しい値"); System.out.println("newValue では、HashCode = " + value.hashCode() + ", value = " + value.getValue()); } public static voidmodifyValue(Value value) { value.setValue("新しい値"); System.out.println("modifyValueでは、ハッシュコード = " + value.hashCode() + "、値 = " + value.getValue()); }
3. 簡単なテストコード
public static void main(String[] args) { Value value1 = new Value(); System.out.println("変更前、HashCode = " + value1.hashCode() + ", value = " + value1.getValue() ); // value1 を新しい Value オブジェクトにポイントします newValue(value1); System.out.println("変更後、HashCode = " + value1.hashCode() + ", value = " + value1.getValue() + "/n"); Value value2 = new Value(); System.out.println("変更前、HashCode = " + value2.hashCode() + ", value = " + value2.getValue()); // オブジェクトの set メソッドを使用して、オブジェクトの内部値を変更しますmodifyValue(value2); System.out.println("変更後、HashCode = " + value2.hashCode() + ", value = " + value2.getValue());
4. 実行結果ログ:
変更前、HashCode = 12677476、値 = 値 newValue の場合、HashCode = 33263331、値 = 新しい値 変更後、HashCode = 12677476、値 = 値 変更前、HashCode = 6413875、値 = 値 変更値の場合、HashCode = 6413875、値 =新しい値 変更後、HashCode = 6413875、値 = 新しい値
5. 結果分析:
上記のコードは、非常に一般的なプログラミング パターンです。define | save | ペリフェラル内の値またはオブジェクトを取得し、そのオブジェクトをパラメータとしてメソッドに渡し、メソッド内のオブジェクトのプロパティと動作を変更します。ただし、newValue とmodifyValue の 2 つのメソッドの変更メソッドは、メソッドが呼び出された後の外観からは大きく異なります。この違いをどのように理解すればよいでしょうか?まず、値渡しと参照渡しの概念を確認してみましょう。
* 値渡しとは、関数に引数を渡すと、関数が元の値のコピーを受け取ることを意味します。したがって、関数がパラメーターを変更する場合、コピーのみが変更され、元の値は変更されません。
* 参照渡しとは、引数が関数に渡されるときに、関数が値のコピーではなく、元の値のメモリ アドレスを受け取ることを意味します。したがって、関数がパラメーターを変更すると、(関数ブロックの外側の呼び出しコード内の) パラメーターの元の値も変更されます。
正解: A - Java 関数はパラメータを値で渡します。
ログを分析します。
* ログ出力の最初のセクションでは、value1 パラメータが newValue メソッド内の新しいオブジェクトを指すように変更され、新しいオブジェクトの hashCode と値が出力されます。ただし、newValue メソッドのドメインから飛び出した後は変化しません。これは、値渡しの定義と特性に準拠しています。参照渡しの場合、newValue(Value value) メソッドの呼び出し後に value1 が変更される必要があります。
* 2 番目のログ出力は、modifyValue メソッド内で value2 が setValue 操作を実行することを示しています。hashCode は変更されませんが、modifyValue メソッドのドメインを離れた後、value2 は main メソッド内で変更されます。 C++ を使用したことがある人は、この現象を次のように簡単に理解できます。関数のパラメータを参照で渡す!これは、C++ の参照渡しに非常に似ているためです。しかし、ここがまさに誤解に陥りやすいところです。
2 つのログの異なる現象の背後にある隠れた原理は、Java 言語ではパラメータが値によって渡され、オブジェクトが参照によって渡されるということです。Java で操作されるオブジェクトは実際には操作中のオブジェクトへの参照であり、オブジェクト自体は「ヒープ」に格納されます。そしてオブジェクトの「参照」はレジスタまたは「スタック」に格納されます。
疑似コードでは、newValue メソッドとmodifyValue メソッドの違いを説明します。
newValue{ Value_ref2 = value_ref1; // value_ref1 を value で渡し、value_ref1 のコピーを取得します value_obj2 = new Value(); // value_obj2 が「ヒープ」に作成され初期化されます value_ref2 -> value_obj2 が指します。 value_obj2 value_ref2 - >value_obj2.setValue(“xxx”) // value_obj2値は変更されます。 printValueObj2(); // ここに出力されるのは obj2 の値です。modifyValue{ Value_ref2 = value_ref1 // value_ref1 のコピーを取得します。 value_ref2 ->value_obj1.setValue("xxx "); // value_obj1 の値が変更されます printValueObj1(); // ここに出力されるのは obj1 の値です}
それは十分明らかです! value1_ref1 がパラメーターとして関数に渡されると、関数ドメインで使用するために value1_ref2 のコピーが最初にコピーされます。この時点で、両方の ref は newObject 関数 [value = new Value();] で同じ value_obj コードを指します。 ]実際、value1_ref1 は新しいオブジェクト value_obj2 を指します。この後の set 操作はすべて新しいオブジェクトに対する操作です。modifyValue 関数は set メソッドを通じて value_obj1 を直接操作します。これは newValue 関数とは異なります。
パラメータを値で渡します
メソッドを呼び出すときはパラメータを指定する必要があり、パラメータ リストで指定された順序でパラメータを指定する必要があります。
たとえば、次のメソッドはメッセージを n 回連続して出力します。
public static void nPrintln(String message, int n) { for (int i = 0; i < n; i++) System.out.println(message);}
例 次の例は、値渡しの効果を示しています。
このプログラムは 2 つの変数を交換するメソッドを作成します。
public class TestPassByValue { public static void main(String[] args) { int num1 = 1; int num2 = 2; System.out.println("swap メソッドの前では、num1 は " + num1 + "、num2 は " + num2) ; // スワップ メソッドを呼び出します swap(num1, num2); System.out.println("スワップ メソッドの後、num1 は " + num1 + " および num2 は " + num2); } /** 2 つの変数を交換するメソッド*/ public static void swap(int n1, int n2) { System.out.println("/tInside the swap メソッド"); .out.println("/t/t交換前 n1 is " + n1 + " n2 is " + n2) // n1 と n2 の値を交換します int temp = n1 =; n2; n2 = temp; System.out.println("/t/tn1 は " + n1 + " n2 は " + n2);
上記の例のコンパイルと実行結果は次のとおりです。
スワップメソッド前、num1 は 1、num2 は 2 スワップメソッド内 スワップ前、n1 は 1、n2 は 2 スワップ後、n1 は 2、n2 は 1 スワップメソッド後、num1 は 1、num2 は 2
2 つのパラメーターを渡して swap メソッドを呼び出します。興味深いことに、メソッドが呼び出された後、実際のパラメータの値は変化しません。