図1のとおり、メソッド呼び出し側とメソッド定義側では、num
変数という同じ名前を使用していますが、領域は別々に確保され、値自体(ここでは「10
」)のコピーが渡されます。したがって、メソッド定義側で値を変更しても、メソッド呼び出し側に影響することはありません。
では、もしメソッド定義側であるmethod1()
メソッドで加算した結果である「20
」をmain()メソッド側で使用したい場合には、どうしたらいいでしょうか。
これは、戻り値でmain()
メソッド側に返せばOKです。Sample1
クラスを修正したコードを見てみましょう(Sample2.java)。
public class Sample2 { public static void main(String[] args) { int num = 10; num = method1(num); //method1()呼び出しの戻り値をnum変数に再代入する System.out.println("mainメソッド側:" + num); } public static int method1(int num) { //戻り値の型をint型で宣言 num += 10; System.out.println("method1メソッド側:" + num); return num; //return文でnum値を返す } }
prompt>java Sample2 method1メソッド側:20 mainメソッド側:20
7行目のmethod1()
メソッドでは、戻り値の型を「void
」から「int
」が変更されています。また、10行目で処理結果であるnum
値をreturn
文で返すように変更されました。こうして返されてきた値を、main()
メソッドの4行目ではnum
変数に再代入しています。
参照型の場合
次に、参照型の動きをサンプルコードで確認してみましょう。このサンプルは、メソッドの引数に基本データ型であるint
型の配列を使用します(Sample3.java)。ポイントは、配列に格納する値が基本データ型であっても、配列自体は参照型として扱われる点です。
public class Sample3 { public static void main(String[] args) { int[] ary = {10}; method1(ary); System.out.println("mainメソッド側:" + ary[0]); } public static void method1(int[] ary) { ary[0] += 10; System.out.println("method1メソッド側:" + ary[0]); } }
3行目でint
型の配列を用意しています。配列には1つ(値は10
)だけ、要素を入れています。ここのary
変数は、配列を指し示す参照型として扱われることに注意してください。4行目ではmethod1()
メソッドの呼び出し時に、このary
変数を指定しています。
8行目では、メソッドの引数で受け取った配列の1番目の要素に10
を加算し、9行目で「20
」の出力後、処理は呼び出し元に戻り5行目が実行されますが、出力結果は「20
」となっています。
prompt>java Sample3 method1メソッド側:20 mainメソッド側:20
基本データ型を使用したSample1.javaサンプルとは実行結果が異なりますね。 これは、メソッドの引数や戻り値に参照型を使用した場合、参照情報のコピーがやり取りされるからです。
参照型変数には、実体となるオブジェクトを指し示す情報(つまりメモリアドレスのようなもの)が格納されています。引数や戻り値に参照型変数を使用すると、オブジェクト自体のコピーではなく、「この場所を指し示してますよ」という参照情報のコピーがやり取りされれます。その結果、異なる位置(異なる参照変数)から同じオブジェクトにアクセスすることになります。
このように、メソッドの引数に基本データ型の変数で値を渡した場合、呼び出し先であるメソッド内の処理で引数の値を変更しても、呼び出し元の変数の値は変更されません。一方、参照型の変数で値を渡した場合、参照を使ってメソッド内でも同じオブジェクトを参照するため、呼び出し先であるメソッド内で値を変更すると、呼び出し元の変数が指す値も変更されます。この挙動は、戻り値で使用した場合も同じです。