問題の背景:
昨日同僚が書いたインターフェースをテストしたところ、こんな問題が見つかりました
上の図の最初のステップ: lhygTaskMode = null で、それを checkParam メソッドに渡して割り当てます。最後のメソッドが実行された後も、lhygTaskMode は null のままです。
問題の原因:
java にはパラメーターを渡す方法が 1 つしかないため、値の受け渡しです。
値渡しでは、実パラメータの値が仮パラメータに渡され、メソッド本体での仮パラメータへの代入操作は実パラメータに影響しません。
テストケース:
次に、特定の出力を確認するためのテスト ケースを作成します。
public class Test {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
Test a = null;
changeObj(a);
System.out.println(a);
}
public static void changeObj(Test a) {
a = new Test();
System.out.println("changeObj>>"+a);
}
}
上記のコードを実行した場合の出力は次のとおりです。
メソッドの内部オブジェクトが割り当てられた後、オブジェクト アドレスが出力されますが、メソッドが実行された後、ソース オブジェクト a はまだ null であることがわかります。
次に、ソース オブジェクトの属性値を変更した後の出力結果を再度テストします。
package com.btonline365.support.test;
public class Test {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
// Test a = null;
// changeObj(a);
// System.out.println(a);
Test a = new Test();
a.setName("王五");
changeObjValue(a);
System.out.println(a.name);
}
public static void changeObj(Test a) {
a = new Test();
System.out.println("changeObj>>"+a);
}
public static void changeObjValue(Test a) {
a.setName("李四");
System.out.println("changeObjValue>>"+a.name);
}
}
出力は次のとおりです。
ここで、属性値が Wang Wu から Li Si に変更されました。
次に、2回目のテストで仮パラメータの属性値が変更されましたが、なぜ仮パラメータが実パラメータの属性値を変更したのでしょうか?
仮パラメーターへの代入操作は実パラメーターに影響しませんが、仮パラメーターのフィールドまたは要素 (仮パラメーターが配列の場合) への代入操作は実パラメーターに影響します。
補足:
値渡しとは、関数を呼び出すときに実際のパラメーターを関数にコピーすることを指します。そのため、関数内でパラメーターが変更されても、実際のパラメーターは影響を受けません。
参照渡しとは、関数が呼び出されたときに実パラメータのアドレスが関数に直接渡されることを意味し、関数内のパラメータの変更は実パラメータに影響します。
要約すると、値渡しと参照渡しの違いの重要なポイントは何ですか。
値渡し |
参照渡し |
|
根本的な違い |
コピーを作成します |
コピーを作成しない |
全て |
関数内で元のオブジェクトを変更することはできません |
元のオブジェクトは関数で変更できます |
シナリオの説明:
あなたが鍵を持っていて、友達が家に来たときに、鍵を渡すだけなら、これは参照渡しです。この場合、彼が鍵に彼の名前を刻印するなど、鍵に何かをした場合、鍵が返されたときに、あなた自身の鍵にも彼の名前が刻印されます。
あなたは鍵を持っています. 友人があなたの家に行きたいと思ったとき, あなたは彼のために新しい鍵を偽造します, そしてあなた自身のものはまだあなたの手の中にあります. この場合、彼がキーに対して何をしても、あなたの手札にあるキーには影響しません。
しかし、上記の状況に関係なく、友人はあなたが渡した鍵を盗み、あなたの家に侵入し、あなたのテレビを壊しました。それで、あなたは影響を受けないと言いますか?
public static void main(String[] args) {
Test a1 = new Test();
System.out.println("源对象初始地址:"+a1);
changeObj(a1);
System.out.println(a1);
}
public static void changeObj(Test a) {
a = new Test();
System.out.println("changeObj>>"+a);
}
上記で、オブジェクトのアドレス値が変更されていないことがわかります。
この図を少し説明すると、main で Test オブジェクトを作成すると、ヒープにメモリの一部が開かれます。A1 は、そのメモリのアドレス@15db9742を保持します(図 1)。changeObjメソッドを呼び出そうとすると、仮引数aに実引数としてa1が渡され、aにはアドレス@15db9742が与えられ、このときaもこのアドレスを指している(図2)。その後、パラメータがchangeObjメソッドで変更されると、つまり a=new Test(); と、@6d06d69c メモリの一部が再度開かれ、a に割り当てられます。それ以降に a を変更しても、メモリ@15db974の内容は変更されません(図 3)。
上のような転送とは? 絶対に参照転送ではない. 参照転送であれば a=new Test() のとき, 実パラメータの参照も @15db974 を指すように変更する必要がある.しません。
この概念から、ここでは実パラメータの参照のアドレスをコピーして仮パラメータに渡すこともわかります。したがって、上記のパラメータは実際には値渡しされ、実パラメータ オブジェクトが参照するアドレスが値として仮パラメータに渡されます。
したがって、値渡しと参照渡しの違いは、渡されるものではありません。実パラメータを仮パラメータにコピーするかどうかです。実パラメータの内容が影響を受けるかどうかは、何を渡すかで判断しますが、アドレスを渡す場合は、アドレスの指すオブジェクトの変化ではなく、アドレスの変化が影響するかどうかで判断します. 鍵と家の関係のようなものです。
所以说,Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。