Javaパラメータ転送-参照転送vs.値転送
2237 ワード
Javaの変数タイプは、基本タイプと参照タイプの2つに大きく分けられます.の基本タイプはint、long、short、charなどの全小文字です. 引用タイプは、String、Integer、Userなど、頭文字が大きい.
参照タイプには、String、Integerなどの「可変参照タイプ」もあります.基本タイプがメソッドのパラメータとして渡されるのは値そのもので、問題ありません.参照タイプがメソッドのパラメータとして渡されるのはアドレスであり,以下の例を参照する.Demo1
changeValueメソッドを呼び出すと、変数sが指す文字列「abc」のアドレス3 aがローカル変数strに渡され、strも文字列「abc」を指す.JavaではStringは変更できませんが、Stringタイプ変数の値を変更すると、文字列定数プールに新しい文字列「abccde」を作成するしかありません.このときstrは、アドレス3 bを介して文字列定数「abccde」を指す.一方、sは、アドレス3 aを介して文字列定数「abc」を指す.従って、呼び出し側出力sの値は「abc」(変更なし)である.
Demo2
changeValueが呼び出されると、同様にsbが指すオブジェクトのスタックメモリアドレス3 aがローカル変数strに渡され、このときstrもそのブロックアドレスを指す.次にstrのappendメソッドを呼び出すと,このスタックメモリ領域に文字列「cde」が追加され,3 aでのオブジェクト自体が変更される.従って、呼び出し端からsbが出力されると、出力3 aにおけるオブジェクトを示すので、変更後の値が出力される.
Demo3
swapメソッドを呼び出すと、sb 1が指すオブジェクトのメモリアドレス3 a、sb 2が指すメモリアドレス3 bがそれぞれ局所変数s 1,s 2に渡される.次に、中間局所変数sbによりs 1とs 2の値が交換され、交換後s 1はメモリアドレス3 b、s 2はメモリアドレス3 aを指す.一方、sb 1〜sb 2が指すメモリアドレスは、sb 1〜>3 a、sb 2〜>3 bに変更されていない.したがって、呼び出し側出力の場合、sb 1は「111」を出力し、sb 2は「222」を出力する.
結論
Javaではパラメータの伝達はすべて値伝達であり,参照伝達は存在しないと言われている.そう思わない人もいる.しかし,パラメータ伝達の本質を理解すればよい.
まず、基本タイプのパラメータは、基本タイプの変数がJVMのスタックメモリに存在するため、値そのものに違いありません.スタックメモリアドレスの概念は存在しません.
次に、参照タイプのパラメータ(可変参照タイプでも非可変参照タイプでも)は、変数が指すスタックメモリのアドレスを渡します.メソッドを呼び出すと、このアドレスの値がメソッドのローカル変数に割り当てられ、このローカル変数も対応するスタックメモリを指します.
ただし、可変参照タイプのパラメータであれば、ローカル変数に新しい値を割り当てると、本質的に新しいメモリ領域を開いて新しい値を入れ、ローカル変数が新しいメモリ領域を指すようにするので、呼び出し側変数の値は変更されません.
一方、可変参照タイプのパラメータであれば、オブジェクトの内容を変更すると、変更はそのオブジェクトが存在するメモリの値であるため、呼び出し側読み出し時に変更された値である.
参照タイプには、String、Integerなどの「可変参照タイプ」もあります.基本タイプがメソッドのパラメータとして渡されるのは値そのもので、問題ありません.参照タイプがメソッドのパラメータとして渡されるのはアドレスであり,以下の例を参照する.Demo1
String s = "abc";
changeValue(s);
System.out.println(s); //abc
public static void changeValue(String str){
str+="cde";
}
changeValueメソッドを呼び出すと、変数sが指す文字列「abc」のアドレス3 aがローカル変数strに渡され、strも文字列「abc」を指す.JavaではStringは変更できませんが、Stringタイプ変数の値を変更すると、文字列定数プールに新しい文字列「abccde」を作成するしかありません.このときstrは、アドレス3 bを介して文字列定数「abccde」を指す.一方、sは、アドレス3 aを介して文字列定数「abc」を指す.従って、呼び出し側出力sの値は「abc」(変更なし)である.
Demo2
StringBuffer sb = new StringBuffer("abc");
changeValue(sb);
System.out.println(sb); //abccde
public static void changeValue(StringBuffer str){
str.append("cde");
}
changeValueが呼び出されると、同様にsbが指すオブジェクトのスタックメモリアドレス3 aがローカル変数strに渡され、このときstrもそのブロックアドレスを指す.次にstrのappendメソッドを呼び出すと,このスタックメモリ領域に文字列「cde」が追加され,3 aでのオブジェクト自体が変更される.従って、呼び出し端からsbが出力されると、出力3 aにおけるオブジェクトを示すので、変更後の値が出力される.
Demo3
StringBuffer sb1 = new StringBuffer("111");
StringBuffer sb2 = new StringBuffer("222");
swap(sb1, sb2);
System.out.println("sb1="+sb1);
System.out.println("sb2="+sb2);
public static void swap(StringBuffer s1, StringBuffer s2){
StringBuffer sb = s1;
s1=s2;
s2=sb;
}
swapメソッドを呼び出すと、sb 1が指すオブジェクトのメモリアドレス3 a、sb 2が指すメモリアドレス3 bがそれぞれ局所変数s 1,s 2に渡される.次に、中間局所変数sbによりs 1とs 2の値が交換され、交換後s 1はメモリアドレス3 b、s 2はメモリアドレス3 aを指す.一方、sb 1〜sb 2が指すメモリアドレスは、sb 1〜>3 a、sb 2〜>3 bに変更されていない.したがって、呼び出し側出力の場合、sb 1は「111」を出力し、sb 2は「222」を出力する.
結論
Javaではパラメータの伝達はすべて値伝達であり,参照伝達は存在しないと言われている.そう思わない人もいる.しかし,パラメータ伝達の本質を理解すればよい.
まず、基本タイプのパラメータは、基本タイプの変数がJVMのスタックメモリに存在するため、値そのものに違いありません.スタックメモリアドレスの概念は存在しません.
次に、参照タイプのパラメータ(可変参照タイプでも非可変参照タイプでも)は、変数が指すスタックメモリのアドレスを渡します.メソッドを呼び出すと、このアドレスの値がメソッドのローカル変数に割り当てられ、このローカル変数も対応するスタックメモリを指します.
ただし、可変参照タイプのパラメータであれば、ローカル変数に新しい値を割り当てると、本質的に新しいメモリ領域を開いて新しい値を入れ、ローカル変数が新しいメモリ領域を指すようにするので、呼び出し側変数の値は変更されません.
一方、可変参照タイプのパラメータであれば、オブジェクトの内容を変更すると、変更はそのオブジェクトが存在するメモリの値であるため、呼び出し側読み出し時に変更された値である.