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

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

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

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

Q&A

解決済

4回答

1945閲覧

Java メソッドの参照渡しがどうしても理解できません!!どなたかお教えください。

happykeikin

総合スコア3

Java

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

0グッド

1クリップ

投稿2021/05/14 18:09

編集2021/05/15 19:17

今月末Java Silver を受験予定で参照渡しが理解できなくて行き詰まっています!!
どなたかわかりやすくご説明できる方助けてください。

13行目がどうして0が表示されるかが理解できません。
2行目で int[] other = { 10 }; となっているので10が表示されると考えてしまいます。
実際に動かすとたしかに0が表示されます。

どうしても理解できません。(汗)

1  static void method1(int[] a) {
2  int[] other = { 10 };
3  a = other;
4  }
5  static void method2(int[] a) {
6  a[0] = 100;
7  }
8  public static void main(String[] args) {
9  int[] array = { 0 };
10 System.out.println(array[0]); // => 0
11
12 method1(array);
13 System.out.println(array[0]); // => 0
14
15 method2(array);
16 System.out.println(array[0]); // => 100
17}

追記

ご回答してくださった方々本当にありがとうございます!
アドバイスをもとに、自分なりに図を書いてみました。
私の勉強不足でまだ腑に落ちていないような気がします。
この図のような認識であっているでしょうか?

イメージ説明

そもそも、この問題は参照渡しが理解できないというより

「参照渡し」と「参照の値渡し」の違いが理解できていないという事だったのですね。

メソッド1(参照の値渡し)
記述が省略してあるがnewしているので参照の値渡し → 呼び出し元の値は変わらない。

メソッド2は(参照渡し)
こちらは参照先の値が共通なので呼び出し元の値も変わる。

みなさんはこれはこういうものだって割り切って理解しているのでしょうか?
なんかもっとスッキリしたいな~


もう少しで納得しそうです。本当に皆様ありがとうございます。

12行目でメソッド1にarrayを渡していますがこれは、あくまで実態ではなく参照値のコピー
ここでもし実態を渡していたら(javaではありえませんが)aとarrayは同一のものになり

3行目の a = other;  の処理で同じところが書き換えられarrayに反映するかと思うのですが、これがコピーだから影響ないという認識で間違いないでしょうか?

このような処理をC言語やC++での参照渡しでおこなったらどうなるのでしょうか?
お詳しい方いたら教えていただけると助かります。  


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

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

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

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

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

dodox86

2021/05/17 00:59

2021/05/16 04:17]の質問編集を読んで: ※質問編集の通知が無かったので、回答やコメントされている方々に編集追記が伝わっていないかもしれませんよ。私はたまたま「なかなか質問閉じないな?」と思って覗いたので気が付きましたが。 > これがコピーだから影響ないという認識で間違いないでしょうか? その認識自体は間違いないですが、そもそも「参照の値渡し」云々の前に、Javaのメソッドの実引数、仮引数とはどういうものかを理解すれば自ずと分かると思います。加えて、momon-gaさんの回答中のコメント「参照渡しがどうというより配列変数を変更することと、配列の中身を変更するの違いが理解できていない」と言う指摘もあたっているかんじもします。 > このような処理をC言語やC++での参照渡しでおこなったらどうなるのでしょうか? これは、プログラミング言語が違うものを例にしても意味が無いのでは。何より、質問者さんのそれらの言語の習熟度が分からないことには、その説明が伝わるとも限りません。ちなみに少なくともC言語には世にいう「参照渡し(call by reference)」はありません。「値渡し(call by value)」のみです。
happykeikin

2021/05/17 03:14

いろいろとご丁寧にアドバイスありがとうございました。 大変勉強になりました。
guest

回答4

0

ベストアンサー

Javaのメソッドから見て、渡された引数は「仮引数」と言い、値を収める器、つまり変数は別物です。呼び出し側が参照を渡しても、渡された方はその値のコピーを仮引数と言う別の器で受け取っています。

12行目のmethod1(array);arrayの参照の値はmethod1メソッドに確かに渡されます。ですが、method1int[] aとして受け取ったaは呼び出し側の実引数であるarrayの参照は入ってはいるものの、aと言う変数の器は別です。a = other;でその器にotherの参照を代入しても、その別の器であるaに収まった値が上書きされるだけです。呼び出し側のarrayには影響しません。ですので、結果0が出力されます。


質問文中の[2021/05/15 06:51]の編集追記内容を読んで:

なぜメソッド1の取り側aが別物になりメソッド2のaは[]をつけたとたんおなじところを参照するようになるかが納得いきません

コードの見た目、字面に惑わされてしまっているのではないでしょうか。

先の回答でも同じようなことを書きましたが、int[] a;と宣言された場合、aで「int型の配列への参照を格納するaと言う名前の変数」そのものを表し、a[0]で「aと言う名前の変数が保持する参照が指し示すint型の配列要素[0]」そのものを表します。これは単に、Javaの文法の話です。
(とは言え「int[] a = {0, 1, 2};の時、aintの配列を表す。」などど表現するときもあるので、話の文脈次第なところはありますので注意を要します)

a = null;a[0] = 1:などのように=演算子で代入操作が行われるとき、左側(左辺と呼びます)の記載内容に応じて右側(右辺)で取り扱うべき型の解釈もJavaの文法に沿って変わります。

試験対策としては今、見分けられないとまずいと思えてしまう焦りは理解できるのですが、ある程度実際にご自身でいくつもコードを書き、「これはどういったことなのか」と考え続けていると、意外と素直に理解できる時がやって来るものです。あまり積極的な助言でなくてごめんなさい。

投稿2021/05/14 18:36

編集2021/05/15 02:19
dodox86

総合スコア9183

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

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

happykeikin

2021/05/14 18:46

dodox86 さん こんな真夜中に丁寧にご回答してくださり本当にありがとうございます!! 説明していただいた内容は理解できました。 ただその理屈でいうと 今度は、なぜ15行目のmethod2(array);での呼び出しだと100が表示されるのかが理解できなくなってしまいます。 物分りが悪くてすみません、どうしても納得したいです。
dodox86

2021/05/14 19:01

> なぜ15行目のmethod2(array);での呼び出しだと100が表示されるのかが理解できなくなってしまいます。 method2()の場合はa[0]と言う表記で、参照を介した配列の実体へのアクセス、呼び出し側で言うところのarray[0]へのアクセスとなっています。=で代入のアクセスをしているのでまぎらわしいのかもしれませんが、配列の「実体」へのアクセスです。aと言う変数の器への代入にはあたりません。 「変数aに収められた参照が指す配列の実体の、[0]の要素」と書けば分かるでしょうか。
dodox86

2021/05/14 19:14

"変数"と言う「値を収める器」と、"参照"と言う「オブジェクト、インスタンスの実体を指し示す値(C言語で言うところのポインターのようなもの)」の違いを意識する必要があります。
guest

0

まず、main で array が作られます。

main: array -------> { 0 }

method1 が呼ばれると、最初は引数 a は array を指してます。

main: array ---+---> { 0 } | method1: | | a -------+

method1 で other が作られます。

main: array ---+---> { 0 } | method1: | | a -------+ other -------> { 10 }

method1 で a に other を代入すると、a の指す先が変わります。(が、array はそのまま。)

main: array -------> { 0 } method1: a -------+ | other ---+---> { 10 }

method1 から return しても、array はそのままなので、13 行目では 0 が表示されます。

main: array -------> { 0 }

次に method2 が呼ばれると、引数 a は array を指してます。

main: array ---+---> { 0 } | method2: | | a -------+

ここで a[0] を書き換えると、a は array と同じものを指してるので、array[0] も変わります。

main: array ---+---> { 100 } | method2: | | a -------+

method1 から return して array[0] を表示すると 100 が表示されます。

main: array -------> { 100 }

お描きになった図はバッチリだと思いますが、どのへんが納得いかないのでしょうか?
例えばこのコードはどうでしょうか?

java

1public class ArrayTest2 { 2 3 static void method3(int[] a) { 4 int[] other = { 10, 20 }; 5 a[0] = 100; 6 a = other; 7 a[1] = 200; 8 } 9 10 public static void main(String[] args) { 11 int[] array = { 1, 2 }; 12 System.out.println(array[0]); // => 1 13 System.out.println(array[1]); // => 2 14 15 method3(array); 16 System.out.println(array[0]); // => 100 17 System.out.println(array[1]); // => 2 18 } 19}

投稿2021/05/14 19:14

編集2021/05/14 22:18
hoshi-takanori

総合スコア7895

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

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

happykeikin

2021/05/14 22:47

ありがとうございます。 徹夜で考えて頭スパークしそうです笑。 本当にありがとうございます。 一旦寝て、スッキリしてまた頂いた問題考えます。 Javaって面白いですね。考えるの好きです。(^^)
guest

0

参照渡しじゃないということが、わかったので解決すると思いますが。
結局1つのスコープで以下のことが行われているのと変わりません。

java

1static void method1(int[] a) { 2 int[] other = { 10 }; 3 a = other; 4} 5 6static void method2(int[] b) { // mainメソッドにあわせて仮引数の名前を変更 7 b[0] = 100; 8} 9 10public static void main(String[] args) { 11 int[] array = { 0 }; 12 System.out.println(array[0]); // 0 13 14 // method1 15 int[] a = array; // static void method1(int[] a) の部分 16 int[] other = { 10 }; 17 a = other; // arrayがotherに置き換わるわけではない 18 System.out.println(array[0]); // 0 19 20 // method2 21 int[] b = array; // static void method2(int[] b) の部分 22 b[0] = 100; 23 System.out.println(array[0]); // 100 24}

このmainの動きが理解できないと、参照渡しがどうというより
配列変数を変更することと、配列の中身を変更するの違いが理解できていないかと思います。

投稿2021/05/15 16:32

momon-ga

総合スコア4820

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

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

0

ご回答してくださった方々本当にありがとうございます!
アドバイスをもとに、自分なりに図を書いてみました。
私の勉強不足でまだ腑に落ちていないような気がします。
この図のような認識であっているでしょうか?

イメージ説明

投稿2021/05/14 21:13

happykeikin

総合スコア3

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

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

m.ts10806

2021/05/14 21:32

「回答」にするより質問に追記されたほうが良いのでは。
happykeikin

2021/05/14 21:53

ありがとうございます!!! 一度回答した内容は削除できないのですね? 質問に追記いたしました!!! 以後気をつけます!!!!!
m.ts10806

2021/05/14 21:56

回答の削除依頼は可能と思います。 投稿の削除ポリシーは確かにあります。 https://teratail.com/help/delete-policy もし「機能が解放されてない」と出るのでしたら運営に問い合わせを。 ちゃんと事由を伝えられれば削除してもらえます。 今回なら「質問本文に追記すべき内容を回答として投稿してしまった。質問本文に転記したのでこの回答は削除願います」とか。
hoshi-takanori

2021/05/14 22:08

質問の訂正というよりは、質問者の自己回答と考えられますので、これはこれで良いのでは。 ところで、どの辺がまだ納得されてないのでしょうか?
happykeikin

2021/05/14 22:25

3行目を 下記のように修正すると13行目は10が表示されます。 3行目  a = other; 修正後 → a[0] = other[0]; aだと別物なのにa[0]としたらarrayと同じになるのかが不思議です。
hoshi-takanori

2021/05/14 22:29

a や other は配列全体を指していて (a や other という変数には配列のアドレスが入ってる、とも言う)、 a[0] や other[0] は配列の要素 (配列に格納されている値) を指すから、という言い方で伝わりますか?
happykeikin

2021/05/14 22:40

う~徹夜で考えてもう頭がまわんないです笑。 一旦寝てまた起きたら頭を整理してみます。 本当にありがとうございます。(^^)
xebme

2021/05/15 07:40

質問に「参照渡し」とありますが、正しくは「参照値の値渡し」です。メソッド呼び出しで、仮引数 a に実引数arrayの参照値のコピーが代入されます。a に新しい配列の参照値を代入しますが、a はmethod1からリターンすると消滅します。実引数のarrayの参照値は、メソッド呼び出しによって変わることはありません。なぜなら参照値の値渡しだからです。
happykeikin

2021/05/15 09:15

ものすごく参考なりました、ご指摘のとおり参照渡しと参照の値渡しを混同していたのでなかなか理解に苦しんだんだと思います。本当にありがとうございます。
dodox86

2021/05/15 18:40

@質問者さん 質問の[2021/05/15 18:13]の編集・追記を読んで: > メソッド1(参照の値渡し) > メソッド2は(参照渡し) いえ、違います。「参照の値渡し」とはメソッドの呼び出し・仮引数に関しての話です。質問者さんの本回答に対するxebmeさんの[2021/05/15 16:40]のコメントをまだちゃんと理解されていないようです。xebmeさんは、質問の文面中「参照渡し」と言う文言について実はそれは正確ではないと指摘されています。method1もmethod2も仮引数はint[] aなので、同じ「参照の値渡し」と言えるものです。呼び出し元の実引数であるarrayの参照の値をメソッドの呼び出しにあたってコピーし、メソッド中の仮引数であるaに渡すので「参照の値渡し」と言うことができます。method2の中の動きはまた別の話です。
dodox86

2021/05/15 18:56

メソッドに渡す引数について、「参照渡し」と言う言い方に相当する動作はJavaには存在しません。これに関する話題はteratailでも過去、何回か投稿されたものですので、参考として1件、ご案内します。 [Java参照渡しについて - #278732] https://teratail.com/questions/278732 teratailトップページから「Java 参照」で関連する質問回答がいくつもヒットするので、参考にされると良いです。(下手をすると逆に混乱するかもしれないので要注意) 一応念押ししておくと、本件についてmethod2で aとa[0]でなぜ動きが違うのか、ということについては別の話です。(と少なくとも私は思っています)
dodox86

2021/05/15 19:04

細かくてすみませんが念の為。上記2件[2021/05/15 04:01]と[2021/05/15 04:14]の私のコメントでの「参照の値渡し」と言う言葉は、xebmeさんのコメントの「参照値の値渡し」と同じ意味で使っています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問