Javaパラメータ伝達ノット
4536 ワード
コードによって、どのコードが印刷された1と2の順序を逆にすることができるかを判断します.
次のコードを実行すると答えがわかります.
パラメータ伝達を理解するには、まず基本タイプと参照タイプの変数の違いを理解します.基本タイプの変数には、基本タイプの値が格納されます.リファレンスタイプの変数には、メモリのある空間を指すアドレス、すなわちリファレンスタイプの変数がメモリのある場所を指すアドレスが格納されます.基本タイプ変数を「=」で操作すると、int a=0のような変数の値が直接変更されます.a = 33;参照タイプ変数を「=」で操作すると、String a=「aaaaa」などの参照変数に格納されているアドレスが変更されます.a = "bbbb"; aは最初は定数プールのaaaaa文字列を指し,その後は定数プールのbbb文字列を指す.
パラメータ伝達は、この値が基本タイプであってもアドレスであっても、付与されるプロセスです.
この2つの問題の最も主要なのはやはり上述したパラメータ伝達の1つの本質を認識しなければならない.メソッドのパラメータリストでは、識別子は単なる代名詞にすぎません.これらの識別子にだまされてはいけません.例えば、このdieセグメントコードの
private static void function(Demo d1,Demo d2){ Demo temp; temp=d1; d1=d2; d2=temp; }
d 1,d 2は完全にa bで代用できる
private static void function(Demo a,Demo b){ Demo temp; temp = a; a = b; b = temp; }
つまりfunction(d 1,d 2)が呼び出されます.このメソッドの場合、a=d 1,b=d 2です.d 1は変数名で参照変数なので、Demoのd 1というオブジェクトアドレスが格納されているだけでしょう(例えば@0 x 002)では、このとき、d 1の値はaに与えられ、aは同じようにDemoのオブジェクトd 1のアドレスを指し、bはオブジェクトd 2のアドレスを指す.これは2つのコードで同じである.
次に、第2のセグメントコードでは、tempはd 1(temp=a)を指し、aはd 2(a=b)を指し、bはd 1(b=temp)を指す.この過程で局所変数a bが指すメモリアドレスが変更されただけで、d 1 d 2の2つの参照変数の値は変更されない.したがって、d 1はDemoの1つのオブジェクトd 1が存在するメモリアドレス(@0 x 002)を指す、d 2は、Demoのオブジェクトd 1が存在するメモリアドレスd 2を指す.
最初のコードのfunctionメソッドを振り返ってみましょう
private static void function(Demo ff,Demo ee){ int a; a = ff.a; ff.a = ee.a; ee.a = a; }
メソッドボディにローカル変数aが既に存在するため、ここではパラメータリストでd 1,d 2をffとeeで置き換える.このとき、d 1がメモリアドレス@0 x 111 d 2を指してメモリアドレス@0 x 222を指すと仮定すると、functionメソッドが呼び出された後、ffも@0 x 111を指し、eeは@0 x 222を指し、そしてa=ff.aは@0 x 111というアドレスに格納されているDemoのオブジェクトd 1であるのメンバー変数aの値がaという変数、すなわちaの現在の値が1に割り当てられ、その後ff.a=ee.aはDemoの別のオブジェクトd 2のメンバー変数aの値がff.aに割り当てられ、ff.aの値が2になり、ee.a=aはee.aに1を割り当て、この2つの操作でDemoの2つのオブジェクトのメンバー変数aのメモリ内の値が変更されるので、後で印刷するときなお,見た結果,元のd 1.a d 2.aの値1と2はそれぞれ2と1になった.
一般的にネット上で議論されているJavaパラメータ伝達が値伝達なのか引用伝達なのかという問題は、Yolandaの知覚的な回答で理解できると思います.これまで値伝達については、引用伝達には曖昧な概念があっただけなので、このような議論がありました.値伝達と引用伝達は、関数呼び出し時のパラメータの評価戦略(Evealuation Strategy)に属していましたを選択します.これは、関数を呼び出すときに、伝達されたコンテンツのタイプ(値タイプか参照タイプか、値かポインタか)ではなく、評価と値の伝達方法の説明です.つまり、あるパラメータ伝達が値伝達言語であると仮定すると、私はメソッドを呼び出すとき、パラメータ伝達が具体的な整数変数であっても、オブジェクトの参照であっても、値伝達を使用しているという事実を変えることはできません.値伝達の伝達方式は元の値のコピーなので、関数では元のオブジェクトを変えることはできません.転送ではコピーは作成されません.転送方法は元の値なので、関数は元のオブジェクトを変更できます.JavaはPass by valueです.
一部の学生は、オブジェクト内のメンバー変数の値を変えることができるのに、なぜJavaが値伝達であるのか疑問に思うかもしれません.ここでは、元のオブジェクトを変更していません.つまり、転送されたd 1 d 2という2つの参照変数の値を変更していません.私たちは方法の中で2つの新しい変数ff eeを作成し、d 1 d 2が指すメモリアドレスを指しています.このメモリアドレスでオブジェクトの値を変更します.
ここにはまだいくつかの問題があります.
http://www.xuebuyuan.com/897461.html
http://blog.darkmi.com/2010/11/28/1430.html
そして、ここにはString類という特殊な場所があります.
aメモリでは、定数プール内のaaaa文字列を指していますが、aを直接印刷するときに印刷される結果は、他のオブジェクトの参照変数のように、オブジェクトを指すアドレスを印刷するのではなく、Stringタイプの定数プール内の値を直接印刷することができます.Stringは基本タイプのように見えます.Stringクラスを詳しく理解するには、この記事を参照してください.記事.Stringは値タイプですか、参照タイプですか.
Stringクラスは純粋なオブジェクトであり、特殊な点は文字列直接量と文字列定数プールと文字列接合の演算子リロードがあることである.また、基本タイプに関係なく、基本タイプのように見えるのは、主にStringクラスが可変クラスであるためである(構造後は変更できず、自身の状態を変更できる方法は提供されていない).
class Demo{
int a;
public Demo(int a){
this.a=a;
}
}
public class TestQuote{
public static void main(String args[]){
Demo d1=new Demo(1);
Demo d2=new Demo(2);
System.out.println(d1.a);
System.out.println(d2.a);
function(d1,d2);
System.out.println(d1.a);
System.out.println(d2.a);
}
private static void function(Demo d1,Demo d2){
int a;
a=d1.a;
d1.a=d2.a;
d2.a=a;
}
}
class Demo{
int a;
public Demo(int a){
this.a=a;
}
}
public class TestQuote{
public static void main(String args[]){
Demo d1=new Demo(1);
Demo d2=new Demo(2);
System.out.println(d1.a);
System.out.println(d2.a);
function(d1,d2);
System.out.println(d1.a);
System.out.println(d2.a);
}
private static void function(Demo d1,Demo d2){
Demo temp;
temp=d1;
d1=d2;
d2=temp;
}
}
次のコードを実行すると答えがわかります.
パラメータ伝達を理解するには、まず基本タイプと参照タイプの変数の違いを理解します.基本タイプの変数には、基本タイプの値が格納されます.リファレンスタイプの変数には、メモリのある空間を指すアドレス、すなわちリファレンスタイプの変数がメモリのある場所を指すアドレスが格納されます.基本タイプ変数を「=」で操作すると、int a=0のような変数の値が直接変更されます.a = 33;参照タイプ変数を「=」で操作すると、String a=「aaaaa」などの参照変数に格納されているアドレスが変更されます.a = "bbbb"; aは最初は定数プールのaaaaa文字列を指し,その後は定数プールのbbb文字列を指す.
パラメータ伝達は、この値が基本タイプであってもアドレスであっても、付与されるプロセスです.
この2つの問題の最も主要なのはやはり上述したパラメータ伝達の1つの本質を認識しなければならない.メソッドのパラメータリストでは、識別子は単なる代名詞にすぎません.これらの識別子にだまされてはいけません.例えば、このdieセグメントコードの
private static void function(Demo d1,Demo d2){ Demo temp; temp=d1; d1=d2; d2=temp; }
d 1,d 2は完全にa bで代用できる
private static void function(Demo a,Demo b){ Demo temp; temp = a; a = b; b = temp; }
つまりfunction(d 1,d 2)が呼び出されます.このメソッドの場合、a=d 1,b=d 2です.d 1は変数名で参照変数なので、Demoのd 1というオブジェクトアドレスが格納されているだけでしょう(例えば@0 x 002)では、このとき、d 1の値はaに与えられ、aは同じようにDemoのオブジェクトd 1のアドレスを指し、bはオブジェクトd 2のアドレスを指す.これは2つのコードで同じである.
次に、第2のセグメントコードでは、tempはd 1(temp=a)を指し、aはd 2(a=b)を指し、bはd 1(b=temp)を指す.この過程で局所変数a bが指すメモリアドレスが変更されただけで、d 1 d 2の2つの参照変数の値は変更されない.したがって、d 1はDemoの1つのオブジェクトd 1が存在するメモリアドレス(@0 x 002)を指す、d 2は、Demoのオブジェクトd 1が存在するメモリアドレスd 2を指す.
最初のコードのfunctionメソッドを振り返ってみましょう
private static void function(Demo ff,Demo ee){ int a; a = ff.a; ff.a = ee.a; ee.a = a; }
メソッドボディにローカル変数aが既に存在するため、ここではパラメータリストでd 1,d 2をffとeeで置き換える.このとき、d 1がメモリアドレス@0 x 111 d 2を指してメモリアドレス@0 x 222を指すと仮定すると、functionメソッドが呼び出された後、ffも@0 x 111を指し、eeは@0 x 222を指し、そしてa=ff.aは@0 x 111というアドレスに格納されているDemoのオブジェクトd 1であるのメンバー変数aの値がaという変数、すなわちaの現在の値が1に割り当てられ、その後ff.a=ee.aはDemoの別のオブジェクトd 2のメンバー変数aの値がff.aに割り当てられ、ff.aの値が2になり、ee.a=aはee.aに1を割り当て、この2つの操作でDemoの2つのオブジェクトのメンバー変数aのメモリ内の値が変更されるので、後で印刷するときなお,見た結果,元のd 1.a d 2.aの値1と2はそれぞれ2と1になった.
一般的にネット上で議論されているJavaパラメータ伝達が値伝達なのか引用伝達なのかという問題は、Yolandaの知覚的な回答で理解できると思います.これまで値伝達については、引用伝達には曖昧な概念があっただけなので、このような議論がありました.値伝達と引用伝達は、関数呼び出し時のパラメータの評価戦略(Evealuation Strategy)に属していましたを選択します.これは、関数を呼び出すときに、伝達されたコンテンツのタイプ(値タイプか参照タイプか、値かポインタか)ではなく、評価と値の伝達方法の説明です.つまり、あるパラメータ伝達が値伝達言語であると仮定すると、私はメソッドを呼び出すとき、パラメータ伝達が具体的な整数変数であっても、オブジェクトの参照であっても、値伝達を使用しているという事実を変えることはできません.値伝達の伝達方式は元の値のコピーなので、関数では元のオブジェクトを変えることはできません.転送ではコピーは作成されません.転送方法は元の値なので、関数は元のオブジェクトを変更できます.JavaはPass by valueです.
一部の学生は、オブジェクト内のメンバー変数の値を変えることができるのに、なぜJavaが値伝達であるのか疑問に思うかもしれません.ここでは、元のオブジェクトを変更していません.つまり、転送されたd 1 d 2という2つの参照変数の値を変更していません.私たちは方法の中で2つの新しい変数ff eeを作成し、d 1 d 2が指すメモリアドレスを指しています.このメモリアドレスでオブジェクトの値を変更します.
ここにはまだいくつかの問題があります.
http://www.xuebuyuan.com/897461.html
http://blog.darkmi.com/2010/11/28/1430.html
そして、ここにはString類という特殊な場所があります.
public class Test {
public static void change(String s)
{
s = "bbbb";
}
public static void main(String[] args)
{
String a = new String("aaaa"); //String a = "aaaa";
System.out.println(a); // aaaa
change(a);
System.out.println(a); // aaaa
}
}
aメモリでは、定数プール内のaaaa文字列を指していますが、aを直接印刷するときに印刷される結果は、他のオブジェクトの参照変数のように、オブジェクトを指すアドレスを印刷するのではなく、Stringタイプの定数プール内の値を直接印刷することができます.Stringは基本タイプのように見えます.Stringクラスを詳しく理解するには、この記事を参照してください.記事.Stringは値タイプですか、参照タイプですか.
Stringクラスは純粋なオブジェクトであり、特殊な点は文字列直接量と文字列定数プールと文字列接合の演算子リロードがあることである.また、基本タイプに関係なく、基本タイプのように見えるのは、主にStringクラスが可変クラスであるためである(構造後は変更できず、自身の状態を変更できる方法は提供されていない).