質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

3回答

945閲覧

java 引数の参照渡しについて

hompoke15

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2022/01/15 11:56

java silverの資格の勉強をしている者です。
参考書の問題に以下がありました。

public class Test{ public static void main (String[] args) { Test ojb1 = new Test(); Test ojb2 = new Test(); System.out.print(ojb1 == ojb2); ojb2 = operate(ojb1, ojb2); System.out.print(" " + (ojb1 == ojb2)); } static Test operate(Test ojb1, Test ojb2) { Test ojb3 = ojb1; ojb1 = ojb2; return ojb3; } }

コンパイル、実行した結果として正しいものは次のどれですか。1つ選択してください。
A, false false
B, true true
C, false true
D, true false
E, コンパイルエラー


私のイメージだと正解は「A, false false」になると思っていましたが、正解は「C, false true」でした。
operateメソッド内で引数ojb1に対して代入されていますが、参照型のためこの代入はmainメソッド内のojb1に対しても有効だと考えていました。しかし、実際にローカル環境でobj変数を確認してみてもmainメソッド内とoperateメソッド内では別物として扱われているようです。なぜこのような結果になるのでしょうか。

ご回答いただけると幸いです。よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hompoke15

2022/01/15 12:46

以下のような場合は、参照型の引数が直接書き換わるのですが、上の場合と違いがわかりません。 class Test2 { static void x(StringBuilder sb) { sb.append("hoge"); } public static void main(String[] args) { StringBuilder sb = new StringBuilder("sb test"); System.out.println(sb); x(sb); System.out.print(sb); } }
guest

回答3

0

下記のコードはどうなるかわかりますか?

Java

1public class Test{ 2 public static void main (String[] args) { 3 int ojb1 = 1; 4 int ojb2 = 2; 5 System.out.print(ojb1 == ojb2); 6 ojb2 = operate(ojb1, ojb2); 7 System.out.print(" " + (ojb1 == ojb2)); 8 } 9 static int operate(int ojb1, int ojb2) { 10 int ojb3 = ojb1; 11 ojb1 = ojb2; 12 return ojb3; 13 } 14}

実際に実行してみればわかりますが、"false true"と質問と同じです。もしこれが、"false true"にあることが理解でいるのであれば、簡単です。質問のコードとこのコードは実質同じだからです。

質問のタイトルに「参照渡し」という言葉を用いてますが、Javaには「参照渡し」は存在しません。Javaの評価戦略はすべて「値渡し」です。代入でも引数でも「値」のみが渡されます。これは変数がプリミティブ型でも参照型でも同じです。プリミティブ型の場合はプリミティブな値そのものが渡されます。では、参照型はどうなるのかというと、参照値(reference value) という「値」が渡されます。(そのため、Javaの参照型での評価戦略のことを「参照の値渡し」という場合がありますが、これは「値渡し」の一種であることにご注意ください。)

よって、参照型だからと言って難しく考える必要はありません。プリミティブ型と同じように値(参照値)が渡され、値(参照値)が代入されるというわけです。(==は変数の値の比較なので、最初から最後まで値(参照値)のやりとりしかしていないと言うことでもあります。)

投稿2022/01/15 12:45

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hompoke15

2022/01/15 13:09

解答ありがとうございます。んー、とても難しく感じます。すべて値渡しと覚えるのであれば簡単な気がしますが、追記に書いてる例などでは引数に渡している元の変数まで変わってますよね?その違いが分からなくてモヤモヤしています。
raccy

2022/01/16 13:21

追記のコードであっても変数の値(参照値)は何も変わっていません。変わっているのは、変数が指し示す先のオブジェクトです。`sb.append("hoge")`は`sb`という変数の値を変更するのではありません。`sb`の値(参照値)で指し示しているオブジェクトに対して、"hoge"という文字列を追加するという変更するという物です。 参照型(オブジェクト型または配列型)の変数が持っている値(参照値)そのものとそれが指し示す先のオブジェクト(または配列)を混同しないようにしてください。質問のコードのように値だけの操作であれば`int`等のプリミティブ型と同じです。しかし、変数の値では無く、オブジェクトに対する変更が含まれるのであれば、値は変わらないが、オブジェクトは変わってしまっていると言うことがあります。その場合であっても、値(参照値)そのものは`int`等のプリミティブ型と同じようにしか変更やコピーなどはできません。
guest

0

参照型の変数は、その実体がメモリ上のどこにあるかを記憶しているだけです。いわば住所です。
代入や引数で渡すというのは、その住所を教えているだけで、教えた人の記憶が書き換わるわけではありません。

例の場合、operateメソッドを呼び出す際、
mainメソッドの変数obj1,obj2がoperateメソッドの仮引数obj1,obj2に住所を教え、
operateメソッド内でobj1がローカル変数obj3に住所を教えています。
メソッドの結果としてobj3の持っている住所を返し、それをmainメソッドのobj2に教えます。
このobj3が持っていた住所は元をたどればmainメソッドのobj1が持っていた住所で、
mainメソッドのobj1の住所はここまで書き換わっていないため、
obj1とobj2の持っている住所が同一のものになります。

追記の例は、住所のところに行って実体の中身をappendにより書き換えています。

投稿2022/01/16 01:51

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

operateメソッドの引数、obj1, obj2は、引数ではあるけれど、メソッド内ではローカル変数と一緒。つまり、obj3と同列。

  1. Test ojb3 = ojb1;で、obj3にobj1の値を代入。
  2. ojb1 = ojb2;で、obj1にobj2の値を代入。このとき、呼び出し元(main)のojb1にはなにも影響しない。
  3. return ojb3;で、obj1の値が返る。
  4. 呼び出し元(main)のobj2に代入。つまり、呼び出し元のobj2は、obj1と同じ値。
  5. ojb1 == ojb2は、true

ちなみに。こんなソースは、試験問題のためだけのソースであり、実際の現場ではこんなソースは書かない。わたしがレビュアならダメ出しする。

  • メソッドの引数は、final宣言をし、メソッド内で引数には値を代入できないようにする。static Test operate(final Test ojb1, final Test ojb2)
  • ローカル変数も、可能な限りfinal宣言して再代入できないようにする。final Test ojb3 = ojb1;

追記。

hompoke15 2022/01/15 21:51
参照型の引数の場合、書き換えることができると思っていました。
参照型でも書き換わる場合とそうでない場合がある?
できれば"なぜ"そうなるか教えていただけるとありがたいです。

参照先インスタンスの内容を書き換えることはできる。たとえば、Listを引数として取る場合。

  • meB, meCは、引数に新しいインスタンスを代入しているけれど、呼び出し元には影響しない。
  • meAは、引数で受けた参照型(list)の参照先インスタンスの内容を書き換えることができる。
import java.util.ArrayList; import java.util.List; public class Hoge { public static void main(String[] args) { final List<String> listA = new ArrayList<String>(); meA(listA); System.out.println(listA); // [a, b] final List<String> listB = null; meB(listB); System.out.println(listB); // null final List<String> listC = new ArrayList<String>(); meC(listC); System.out.println(listC); // [] } private static void meA(final List<String> list) { list.add("a"); list.add("b"); } private static void meB(List<String> list) { list = new ArrayList<String>(); list.add("a"); list.add("b"); } private static void meC(List<String> list) { list = new ArrayList<String>(); list.add("a"); list.add("b"); } }

投稿2022/01/15 12:26

編集2022/01/16 02:49
shiketa

総合スコア3971

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shiketa

2022/01/15 12:33 編集

たとえ試験の問題であっても、こういうソースに触れてしまうと、その言語ではあたかもこういう書き方を推奨しているかのように勘違いする受験者もいるとおもうので、とてもよくないことだと思います。はい。
hompoke15

2022/01/15 12:51

ありがとうございます。書き方がよろしくないこと承知しました。 参照型の引数の場合、書き換えることができると思っていました。 参照型でも書き換わる場合とそうでない場合がある? できれば"なぜ"そうなるか教えていただけるとありがたいです。
juner

2024/04/10 05:44

参照型 / 値型関係なく、 代入は反映されない。 参照型は変更不可(イミュータブル)な設計思想で作成されていないのであれば参照先の値を変更することはできる為、変更できるってだけなのでは……?ただ、参照渡しは無い為、仮引数への代入は反映されない。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問