参照渡しと値渡し、引数には注意が必要!?
参照渡しと値渡し
引数には注意が必要
前回、プリミティブ型とクラス型についてまとめました。
内容としては、変数であってもプリミティブ型の変数とクラス型の変数によってデータの格納の仕方が異なるため、比較を行うときには注意が必要である。というものです。
今回の内容は、このプリミティブ型の変数とクラス型の変数には比較以外に引数でも注意が必要となります。
私もこの引数で注意を怠り謎の不具合が出たことがあります。これはプログラミングに慣れてきたころに起こるミスだと思います。
参照渡しと値渡しとは
プリミティブ型は箱のイメージなのに対して、クラス型はデータの場所を格納します。そのため引数でデータを渡すときにも、データの値を直接渡すのか、データの場所を渡すのか変わってきます。
- 値渡し
- 参照渡し
プリミティブ型を引数とした時には、この値渡しとなります。
これは、引数に与えられたデータをコピーして、メソッド内で使う変数と、引数に渡した変数は別物として扱われます。
そのためメソッド内で引数の変数の値を変えても、もとの変数の値は変わりません。
クラス型を引数とした時には、この参照渡しとなります。
これは、もとの変数のデータの場所を引数の変数に渡します。そのためメソッド内で引数の変数の値を変えると、メソッドを抜けた後のもとの変数の値も変わったままになります。
class Test { public static void main( String[] args ) { int a = 1; Item b = new Item(); System.out.println( "a=" + a + " b.data=" + b.data ); changeData( a, b ); System.out.println( "a=" + a + " b.data=" + b.data ); } private static void changeData( int _a, Item _b ) { System.out.println( "a=" + _a + " _b.data=" + _b.data ); _a = 5; _b.data = 10; System.out.println( "a=" + _a + " b.data=" + _b.data ); } }
class Item { int data = 9; }これを実行すると以下のように出力されたはずです。
intの変数はメソッド実行後には値が変わっていないのに対して、Itemクラスをインスタンス化した変数はメソッドを抜けたのにも関わらず、値が変化したままです。
これは、引数で変数を渡すときに、もとの変数の場所を共有したことで、メソッド内で加えた変化が、もとの変数にも適用されてしまったためです。
このようにクラス型を引数に渡してした場合には中が必要になります。
ちなみに、Stringはクラス型にもかかわらず、参照渡しではなく値渡しと同じ挙動をします。
class Test { public static void main( String[] args ) { String a = "テスト"; System.out.println( "a=" + a ); changeData( a ); System.out.println( "a=" + a ); } private static void changeData( String _a ) { System.out.println( "_a=" + _a ); _a = "チェンジ"; System.out.println( "_a=" + _a ); } }これを実行すると以下のようになります。
えっ?Stringってクラス型じゃないの?
もちろんクラス型です。しかし、Stringは特殊なようで、値渡しになるようです。
String型はインスタンス化し、そのオブジェクトに値を追加しているわけではいためだそうです。
配列もクラス型
先程クラス型を引数に取るときには注意が必要と言いましたが、配列もクラス型なので同じく注意が必要です。
私は以前行列計算の自作クラスを作成していたときに、引数の配列をそのまま操作し、呼び出し元に戻すという処理を実装していました。そのため意図しない不具合を起こしていました。この参照渡しについて知らなかった私は不具合の修正に時間がかかりました、、、
まとめ
ということで今回は「参照渡しと値渡し」についてまとめました。
メソッドの実装ができるようになってくると、この問題に一度は遭遇すると思います。私は独学ということもあり、プログラミング歴4年目にして遭遇しました。
独学だったため何が原因なのか理解するのに時間がかかりました。
こういうときにプログラミングスクールに通ってるといいのかなぁなんて思います。
まだ私もプログラミング初中級者としていろいろな問題に遭遇すると思いますが、そのときはブログでまとめようと思います!!
では今回はこの辺で、ではまた!