Home > 保険システム開発室NEWS > Javaの仮引数と実引数

Javaの仮引数と実引数

2008-12-19 17:02

前回Javaというオブジェクト指向言語で初心者が犯しやすいポイントとして、Javaのスタックとヒープというお話をしました。
これに関連する話として、本日はJavaの引数に関して仮引数と実引数の動きを簡単にご説明したいと思います。

尚、以降の内容はJavaのスタックとヒープに関して理解していただいた方を前提として記述しております。まだ御覧になってない方は、先に、こちらをご確認いただければと思います。

実引数とは

実引数とは下記のサンプルコードでの、"st"と"sb"の変数を指します。つまりメソッドに渡す呼び出し元の引数のことです。

private void func1( ){

 String st = new String("IT");
 StringBuffer sb = new StringBuffer("ソリューション");

 func2( st, sb );
}

仮引数とは

仮引数とは下記のサンプルコードでの、"st"と"sb"の変数を指します。

private void func2( String st, StringBuffer sb ){

}

Javaでは引数の渡し方は、すべて「値渡し」

引数の仕組みは「参照渡し」や「値渡し」という言い方がありますが、Javaの場合は「値渡し」になります。 Javaの引数は「参照渡し」であると誤解していらっしゃる方が多いようですが、これらの言葉の定義は別にして まずはどのように動作しているかを以下にご説明いたします。

StringBufferを引数にした場合の例

まずはStringBufferを引数とした場合を例に、どのような動きをしているかをご説明します。

private void func1( )
 StringBuffer sb1 = new StringBuffer( "IT" );------ (1)
 func2( sb1 );------ (2)
 System.out.println( sb1 );------ (5)
}
private void func2( StringBuffer sb2 ){------ (3)
 sb2.append( "ソリューション部" );------ (4)
}

下図の通り、(1)でヒープ上にStringBufferのインスタンスが生成され、そこへのアドレスがスタック上の変数sb1に格納されます。

(2) (3) でfunc2メソッドが呼び出されます。Javaではこの時に実引数sb1のアドレスが仮引数sb2にコピーされます。
重要なのは、実引数sb1と仮引数sb2はスタック上では別の領域に存在しているが、格納されているアドレスは同じという事です。
実引数のアドレスのが仮引数にコピーされるので、「値渡し」なのです。

(4)でsb2の変数を使用して値を追加すると、sb1の変数から参照するインスタンスも値が追加される。

(5)でsb1の値を出力すると下記の通り、"ITソリューション部"と出力されます。

サンプルプログラムの実行結果
ITソリューション部

Stringを引数にした場合の例

Stringを引数にするとStringBufferとは異なった挙動を見せます。これはStringは不変オブジェクトであることに起因します。

サンプルプログラムの前に、Stringで重要な性質を以下にご説明します。

String st = "ITソリューション部"; (1)
String st = new String("ITソリューション部"); (2)

上記の(1)と(2)は同じ結果になります。つまり、(1)のようにStringクラスに文字列を代入するということはヒープ上に新しいインスタンスを生成するということになるのです。
※ただし、正確には(1)と(2)は結果に至るまでの挙動が異なります。(1)のように記述したほうがパフォーマンスは良いです。

上記のStringの性質を踏まえて、以下のサンプルプログラムをご説明します。

private void func1( )
 String st1 = "IT";------ (1)
 func2( st1 );------ (2)
 System.out.println( st1 );------ (5)
}
private void func2( String st2 ){------ (3)
 st2 = st2 + "ソリューション部";------ (4)
}

Stringで文字列の代入はインスタンスを生成することになりますので、下図の通り(1)でヒープ上にStringのインスタンスが生成され、そこへのアドレスがスタック上の変数st1に格納される。

(2) (3) でfunc2メソッドが呼び出され、実引数st1のアドレスが仮引数st2にコピーされます。

先に説明したStringの性質を踏まえると、(4)に見られる仮引数st2への代入はヒープ上に新しいインスタンスが生成され、スタックのst2はそこへのアドレスが上書きされてしまいます。 よって、下図の通りst1とst2はヒープ上の別のインスタンスを指すことになります。

(5)でst1の値を出力すると下記の通り、"IT"とだけ出力されます。

サンプルプログラムの実行結果
IT

Javaは「参照渡し」ではない

上記でご説明した通り、Javaの仮引数と実引数ではスタック上の物理的な領域は異なります。 仮引数と実引数はスタック上の同じ領域を指していると勘違いすることにより、大きなバグを生んでしまうことがあるので十分な注意が必要です。

補足

上記で説明した「実引数の値が仮引数にコピーされる」というのは、プリミティブ型の場合も同様です。 プリミティブ型の変数にはアドレスではなく値そのものが保持されていますので、値そのものがコピーされるということになります。

Posted by T.S

このページの上部へ