Java の参照型は「参照の値渡し」(パート1:コード編)

0
791
views

外部メソッドへ引数を渡す方法は色々ありますが、Java の参照型では「参照の値渡し」という方法が使われます。ここでは、ひと言では分かりにくい「参照の値渡し」という現象をコードの側面から見てみます。

3つの事例

Java には、基本型(プリミティブ型)と参照型があります。参照型では、参照の値渡し(Call By Value of Reference)というメソッドの呼び出し方をします。

例をコードで見てみます。

例1:フィールドを書き換える

次のコードは参照型の変数が利用する Obj クラスです。

public class Obj {
    public int num;
}

そして次のコードが、参照型の変数を引数にして外部のメソッドを呼ぶ典型的な例です。

class CallByValueOfReference_basis {
    public static void main(String... args) {
        Obj foo = new Obj();
        foo.num = 128;
        deliver(foo);
        System.out.println(" foo.num = " + foo.num);
    }
    private static void deliver(Obj bar) {
        bar.num = 256;
        System.out.println(" bar.num = " + bar.num);
    }
}
bar.num = 256
foo.num = 256

典型的な例だけ見ると

典型的な例だけ見ると、Java の参照型は「参照渡し」をしているように見えます。

「参照渡し」の特徴

参照渡しは、メソッドの引数に参照を渡す方法です。

参照渡しを行うと、引数 (仮引数) を変更すると元の変数 (実引数) も変更される という現象がおこります。上記のコード実行例では、まさにこのような現象が起きていますね。

この例だけ見れば「Java の参照型は参照渡し」と言えます。しかし実際には、Java は参照渡しを行いません。なぜでしょうか。

例2:new する

今度は、引数で渡したオブジェクトを new してみます。その後は前例と同じようにオブジェクトのフィールドを書き換えます。

class CallByValueOfReference_new {
    public static void main(String... args) {
        Obj foo = new Obj();
        foo.num = 128;
        deliver(foo);
        System.out.println(" foo.num = " + foo.num);
    }

    private static void deliver(Obj bar) {
        bar = new Obj();
        bar.num = 256;
        System.out.println(" bar.num = " + bar.num);
    }
}
bar.num = 256
foo.num = 128

結果を見ると

結果を見ると、元の変数 foo の値が書き換わっています。

参照渡しでは、この現象の説明がつきません。参照渡しであれば、foo.num の値は 256 になるはずだからです。

例3:オブジェクトに null を代入する

もう1つ例を見てみます。今度は引数で渡したオブジェクトに null を代入します。その後はまた同じように、オブジェクトのフィールドの値を書き換えます。

class CallByValueOfReference_null {
    public static void main(String... args) {
        Obj foo = new Obj();
        foo.num = 128;
        deliver(foo);
        System.out.println(" foo.num = " + foo.num);
    }

    private static void deliver(Obj bar) {
        bar = null;
        System.out.println(" bar = null");
    }
}
bar = null
foo.num = 128

なぜこんなことが起こるのか

仮引数(引数で渡されたオブジェクト)のフィールドの値をメソッド内で書き換えると、実引数(引数で渡された元のオブジェクト)のフィールドの値も書き換わる。

それなのに一方では、引数で渡されたオブジェクトをメソッド内で new したり、null を代入した場合は、なぜ書き換わらないのか。

その答えはやはり「Java の参照型は参照の値渡しだから」なのです。

この続きは「Java の参照型は「参照の値渡し」(パート2:処理イメージ編)」につづきます。

Java の参照型は「参照の値渡し」(パート2:処理イメージ編)