【Java】参照値渡しという言葉が悪い!


必ずつまづくJavaの参照値渡し

Javaにおいて、参照渡しは存在しないとよく聞きます。
最初は「えっ」って思いましたが、調べた結果をまとめました。

一般的なメソッドの引数の渡し方

・値渡し
・参照渡し
・参照値渡し

Javaにおけるメソッドの引数の渡し方

・値渡し
・参照値渡し
※「参照渡し」はJavaでは存在しません。
「値渡し」、「参照値渡し」について、説明していきます。

値渡しの例

RefValHandOver.java
private static void editNumber(int arg){
    arg = 0;
    System.out.println("editNumber : " + arg);
}
public static void main(String[] args) {
    int number = 100;
    editNumber(number);
    System.out.println( "main : " + number);
}

結果

editNumber : 0
main : 100

editNumber内では0になっているが、main内では100のままで変わらない。
引数をプリミティブ型にした場合は値渡しとなる。

プリミティブ型

bit 初期値
boolean 1bit false
byte 8bit 0
char 16bit \u0000
short 16bit 0
int 32bit 0
float 32bit 0.0
long 64bit 0
double 64bit 0.0

ここまでは特に問題ないですよね。

参照値渡しの例

3つのパターンに分類して説明していきます。
・1. メソッド内でデータ操作した場合
・2. メソッド内でnewしなおす。
・3. メソッド内でnullを代入する。

RefValHandOver.java
// 1. メソッド内でデータ操作した場合
private static void methodAddArray(ArrayList<String> arg){
    arg.add("B");
    System.out.println("methodAddArray : " + arg.hashCode() + " : " + arg.toString());
}
//2. メソッド内でnewしなおす。
private static void methodNewArray(ArrayList<String> arg){
    arg = new ArrayList<String>();
    arg.add("C");
    System.out.println("methodNewArray : " +arg.hashCode() + " : " +  arg.toString());
}
//3. メソッド内でnullを代入する。
private static void methodNullArray(ArrayList<String> arg){
    arg = null;
    System.out.println((arg != null) ? "methodNullArray : " + arg.hashCode() + " : " +  arg.toString() : "null");
}

public static void main(String[] args) {
    ArrayList<String> arrayList = new ArrayList<String>() {{add("A");}};
    // 1. メソッド内でデータ操作した場合
    methodAddArray(arrayList);
    System.out.println("main : " + arrayList.hashCode() + " : " +  arrayList.toString());

    //2. メソッド内でnewしなおす。
    methodNewArray(arrayList);
    System.out.println("main : " + arrayList.hashCode() + " : " +  arrayList.toString());

    //3. メソッド内でnullを代入する。
    methodNullArray(arrayList);
    System.out.println((arrayList != null) ? "main : " + arrayList.hashCode() + " : " +  arrayList.toString() : "null");

}

結果

// 1. メソッド内でデータ操作した場合
methodAddArray : 3042 : [A, B]
main : 3042 : [A, B]       //参照先が変わっていない

//2. メソッド内でnewしなおす。
methodNewArray : 98 : [C]
main : 3042 : [A, B]       //参照先が変わっている

//3. メソッド内でnullを代入する。
methodNullArray : null
main : 3042 : [A, B]       //参照先が変わっている 

図解してみる

説明してみる

焦点は引数に新しい参照先を代入しているかどうかです。
代入されると「main内のローカル変数」と「メソッド内の引数」が別物になってしまいます。
※Javaには存在しない参照渡しでは2、3の例がmainのローカル変数に反映されます。

まとめ

値渡し参照値渡しについて説明してきました。
個人的には参照値渡しを参照先アドレス渡しとしたら、わかりやすいんじゃないかと思います。