まず、「参照渡し」「値渡し」という言葉は、言語や文脈等によって意味合いが異なることが多く、
うかつにつかうと痛い目を見るので気を付けた方が良いです。
うかつにその単語を出すと、たとえば
・Javaには「参照渡し」はない
・⇔いや、○○という動作を(便宜的に)「参照渡し」といってるだけだ。
・Javaにあるのは「参照(値)の値渡し」でしょ?
・Javaには「参照(値)の値渡し」もない、あるのは値渡しだけだ。
・⇔いや、ある。△△という動作は「参照(値)の値渡し」だ。著名な人もこの意味で使っている
・C言語には本来の意味での「値渡し」「参照渡し」があるよね?
・はあ?何言ってんの?C言語には「参照渡し」なんてないよ。それをいうなら「ポインタ渡し」だろ?
・お前さあ「ポインタ型の値渡し」と「参照渡し」の区別ついてる?
等々といった論争が続くことになります。
したがって、ここでは立ち入りません。
人によっては、質問者さんが引用した教科書の記述は間違ってる、というかもしれませんが、それもここでは立ち入りません。
上っ面の知識で武装して言葉尻をとらえて論破することは生産的とはいえません。
まず大切なのは質問者さんが使おうとしている Java での基本的な原理や挙動を理解することだと思います。
このあたりは下記のページが参考になると思うので、ぜひ一度読んでください。
Java に参照渡しは存在しない。値渡しだけが存在する。
ttps://yoshitaro-yoyo.hatenablog.com/entry/only_value_passing_in_java
「プリミティブ型」と「参照型」はメモリ管理の仕組みが異なる【Java】
ttps://yoshitaro-yoyo.hatenablog.com/entry/memory_management_in_java
上記が難しければ、Java における変数の管理について図でわかりやすくまとめてある下記を一度読んでからもう一度読んでみて下さい。
ttps://freelance-jak.com/technology/java/1175/
上記でも言及されていますが、関係するリファレンスの記述は、ここら辺になりますので、余裕があれば読んでおくことをおすすめします(英語ですが翻訳ソフト等を使えばよいでしょう)
メリット・デメリット
・では、質問者さんが使っている文脈での「"値渡し"」「"参照渡し"」風の動作のメリット・デメリットについて簡単に触れます。
注意:
以下独自用語であるという意味を強調するため二重引用符で囲んだうえ「風の動作」という接尾辞をつけています。
この、「"参照渡し"風の動作」「"値渡し風"の動作」という用語自体、本質問・回答内でしか通用しないものであり、外部に持ち出すべきではありません。
"参照渡し"風の動作
public class Main {
public static void main(String[] args) throws Exception {
int[] array = {1, 2, 3};
methodA(array);
System.out.println(array[0]); // 11が出力されます
}
public static void methodA(int[] num){
num[0] += 10;
}
}
メリット:参照型の変数を渡す際、ポインタ(アドレス)のコピーだけで済むので、コストが小さい。(動作が早くメモリ消費も少ない)
- デメリット:渡し先での挙動に注意する必要あり(渡し元のデータを書き換える場合がある)
"値渡し"風の動作
public class Main {
public static void main(String[] args) throws Exception {
int value = 1;
methodB(value);
System.out.println(value); // 1が出力されます
}
public static void methodB(int num){
num += 10;
}
}
- メリット:値そのものがコピーされるので、書き換えを心配?しなくてよい
- デメリット:
・メソッド間で直感的な意味での値の共有ができない。
・値のコピーにコストがかかる(ただしJavaでは、質問者さんの文脈での「"値渡し"」風の動作になるのは、基本的にプリミティブ型の変数を渡すときだけなので、実際のコストは問題になりにくい。[ミュータブル・イミュータブルの挙動違いについてはここでは深入りしません])
ただ、実際上記のようにメリットデメリットというくくりで論じるのはあまり適切ではないかなとも思います。
というのは、Java では基本的に、プリミティブ型の変数を渡す場合は、"値渡し"風の動作となり、参照型の変数(その変数が指し示している先がオブジェクト[=クラスのインスタンス、配列]等であるもの)を渡す場合は、"参照渡し"風の動作となり、実質的に選択できないからです。[ミュータブル・イミュータブルの違いによる、渡した後での挙動の違いはここでは深入りしません]
たとえば、参照型の変数を渡したときに"値渡し"風の動作をさせたいのであれば、コピー用のメソッドを使うか、自分で中身をコピーする処理を書く必要があります。
(また、同じ参照型でも、ミュータブルなオブジェクトとイミュータブルなオブジェクトでも、渡した後の処理によっては挙動が異なってくる場合がありますので、そこもおさえておいた方が良いと思います。
この辺は下記がわかりやすいと思います。
ttps://medium-company.com/java-プリミティブ型-参照型/
)
なぜメソッドへの変数の渡し方にこのような違いがあるのか?
歴史的な経緯として、C言語のような歴史の長い言語の一部(古いものだけではなく、たとえば最近の言語だとGolangなども含む)は、ポインタ(のようなもの)を使って"値渡し風"の動作と"参照渡し"風の動作を選択できます。
どちらかといえば、"値渡し風"の動作が既定の動作です。
しかし、巨大なサイズの構造体(オブジェクトのようなもの)に対して"値渡し風"の動作を行うと、都度コピーが必要になり遅くなりメモリを圧迫するというデメリットがあります。
また、一般的に、巨大なサイズの構造体に対して"値渡し風"の動作を行う必要性のある場面も少ない、という事情があったと考えられます。(なので構造体に対してはポインタを使って"参照渡し"風の動作をさせることが多い)
一方、単純な値(プリミティブ型のようなもの)については、コピーのコストが少ないです。また、仮に単純な値に対してまで"参照渡し"風の動作を行うと、意図せず渡し元の値を書き換えてしまうリスクがある(=設計上、単純な値は渡し元を書き換えたくない・書き換える必要がない場面が多い)と考えられます。
なので、Java では、プリミティブ型は"値渡し"風、参照型は"参照渡し"風の動作になったのではないか、と思われます。
(あくまで推測です)