Javaパラメータ転送-参照転送vs.値転送

2237 ワード

Javaの変数タイプは、基本タイプと参照タイプの2つに大きく分けられます.
  • の基本タイプはint、long、short、charなどの全小文字です.
  • 引用タイプは、String、Integer、Userなど、頭文字が大きい.

  • 参照タイプには、String、Integerなどの「可変参照タイプ」もあります.基本タイプがメソッドのパラメータとして渡されるのは値そのもので、問題ありません.参照タイプがメソッドのパラメータとして渡されるのはアドレスであり,以下の例を参照する.Demo1
    String s = "abc";
    changeValue(s);
    System.out.println(s); //abc
    
    public static void changeValue(String str){
        str+="cde";
    }
    

    changeValueメソッドを呼び出すと、変数sが指す文字列「abc」のアドレス3 aがローカル変数strに渡され、strも文字列「abc」を指す.JavaではStringは変更できませんが、Stringタイプ変数の値を変更すると、文字列定数プールに新しい文字列「abccde」を作成するしかありません.このときstrは、アドレス3 bを介して文字列定数「abccde」を指す.一方、sは、アドレス3 aを介して文字列定数「abc」を指す.従って、呼び出し側出力sの値は「abc」(変更なし)である.
    Demo2
    StringBuffer sb = new StringBuffer("abc");
    changeValue(sb);
    System.out.println(sb); //abccde
    
    public static void changeValue(StringBuffer str){
        str.append("cde");
    }
    

    changeValueが呼び出されると、同様にsbが指すオブジェクトのスタックメモリアドレス3 aがローカル変数strに渡され、このときstrもそのブロックアドレスを指す.次にstrのappendメソッドを呼び出すと,このスタックメモリ領域に文字列「cde」が追加され,3 aでのオブジェクト自体が変更される.従って、呼び出し端からsbが出力されると、出力3 aにおけるオブジェクトを示すので、変更後の値が出力される.
    Demo3
    StringBuffer sb1 = new StringBuffer("111");
    StringBuffer sb2 = new StringBuffer("222");
    swap(sb1, sb2);
    System.out.println("sb1="+sb1);
    System.out.println("sb2="+sb2);
    
    public static void swap(StringBuffer s1, StringBuffer s2){
        StringBuffer sb = s1;
        s1=s2;
        s2=sb;
    }
    

    swapメソッドを呼び出すと、sb 1が指すオブジェクトのメモリアドレス3 a、sb 2が指すメモリアドレス3 bがそれぞれ局所変数s 1,s 2に渡される.次に、中間局所変数sbによりs 1とs 2の値が交換され、交換後s 1はメモリアドレス3 b、s 2はメモリアドレス3 aを指す.一方、sb 1〜sb 2が指すメモリアドレスは、sb 1〜>3 a、sb 2〜>3 bに変更されていない.したがって、呼び出し側出力の場合、sb 1は「111」を出力し、sb 2は「222」を出力する.
    結論
    Javaではパラメータの伝達はすべて値伝達であり,参照伝達は存在しないと言われている.そう思わない人もいる.しかし,パラメータ伝達の本質を理解すればよい.
    まず、基本タイプのパラメータは、基本タイプの変数がJVMのスタックメモリに存在するため、値そのものに違いありません.スタックメモリアドレスの概念は存在しません.
    次に、参照タイプのパラメータ(可変参照タイプでも非可変参照タイプでも)は、変数が指すスタックメモリのアドレスを渡します.メソッドを呼び出すと、このアドレスの値がメソッドのローカル変数に割り当てられ、このローカル変数も対応するスタックメモリを指します.
    ただし、可変参照タイプのパラメータであれば、ローカル変数に新しい値を割り当てると、本質的に新しいメモリ領域を開いて新しい値を入れ、ローカル変数が新しいメモリ領域を指すようにするので、呼び出し側変数の値は変更されません.
    一方、可変参照タイプのパラメータであれば、オブジェクトの内容を変更すると、変更はそのオブジェクトが存在するメモリの値であるため、呼び出し側読み出し時に変更された値である.