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

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

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

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

Q&A

解決済

3回答

1540閲覧

Java参照渡しについて

kobe2018

総合スコア21

Java

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

0グッド

0クリップ

投稿2020/07/18 14:20

以下のコードがいまいち理解できません。
自分なりの解釈を書いてみたので合っているか教えてください。

Java

1public class Main { 2 public static void main(String[] args) { 3 String s = "abc"; 4 method(s); 5 System.out.println(s); 6 } 7 8 public static void method(String s) { 9 s = s + "def"; 10 } 11 12}

実行結果は以下です。

abc

methodメソッドではsに新しい値を入力していると思いました。
methodメソッドは以下のようなことをやっているという解釈であってますか。

s = new String(s + "def");

つまり参照先を新しくしている。
そのため、mainメソッドのsには関係がなくなる。

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

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

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

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

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

guest

回答3

0

Javaは参照渡しではないため、新たなオブジェクトを仮引数に代入しても呼び出し元側の実引数は変更されません。Stringが不変とかそういうのは今回は全く関係無いです。

まず、Javaでは、Stringオブジェクトや文字列リテラルに対する+演算子(String Concatenation Operator +と言われる)は結合された新たなStringを生成します。一般的なJDKの実装では、StringBuilder(昔はStringBuffer)を用いて文字列を結合し、最後にStringに変換するという処理を行っています。つまり、s + "def"は新たな別のStringです。それを、仮引数sに代入していることになりますが、これは呼び出し元の実引数sとは別物です。methodメソッドにおいて、全てのsxに変えても同じ動きをすることからもそれはわかるでしょう。たまたま名前が同じなだけなので、ここは混同しないでください。そして、Javaでのメソッドの引数渡しは全て値渡しであるため、仮引数に新たな値を代入しても、実引数側には何も影響を与えないと言うことです。

これはStringが不変とかは関係ありません。例えば、可変であるStringBuilderであっても、結果は同じです。

Java

1public class Main { 2 public static void main(String[] args) { 3 var s = new StringBuilder("abc"); 4 method(s); 5 System.out.println(s); 6 } 7 8 public static void method(StringBuilder s) { 9 var x = new StringBuilder(); 10 x.append(s.toString()); 11 x.append("def"); 12 s = x; 13 } 14}

しかし、StringBuilderの場合は、次のように書くと結果が変わります。(Stringは不変であるため、このような書き方はできません。)

Java

1public class Main { 2 public static void main(String[] args) { 3 var s = new StringBuilder("abc"); 4 method(s); 5 System.out.println(s); 6 } 7 8 public static void method(StringBuilder s) { 9 s.append("def"); 10 } 11}

こちらは"abcdfe"となるはずです。これはオブジェクトそのものを変更しているためです。Javaの参照型では、変数が持つのが参照値であり、それを値渡しで渡しているため、このようなことが可能です。このようなことができる値渡しを「参照の値渡し」(共有渡し、オブジェクト渡し、call by share、call by object、call by object-sharing、また、渡しではなく呼び、call byではなくpass byという表現もあり、今のところ定まった一般的な訳語がない)と呼ばれます。

では、C++やC#の参照渡しの場合はどうなるのかというと、実際に見てみましょう。(C++だとオブジェクトの持ち方がJavaと違うので似た仕組みになっているC#を使います。)

C#

1public class Test { 2 public static void Main() { 3 var s = "abc"; 4 method(ref s); 5 System.Console.WriteLine(s); 6 } 7 8 public static void method(ref string s) { 9 s = s + "def"; 10 } 11}

stringはJavaのString相当で参照型の不変な文字列オブジェクトで、refは参照渡しであることを示しています。参照渡しであるため、仮引数への代入によって実引数も変更され、結果は"abcdef"となります。逆に、参照渡しではなく、Javaと同じく値渡しにした場合を見てみましょう。

C#

1public class Test { 2 public static void Main() { 3 var s = "abc"; 4 method(s); 5 System.Console.WriteLine(s); 6 } 7 8 public static void method(string s) { 9 s = s + "def"; 10 } 11}

Javaと同じく"abc"になります。

各コードはpaiza.ioで確認してみてください。

投稿2020/07/18 15:32

raccy

総合スコア21733

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

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

0

s = s + "def";

上記操作を行いたい場合は StringBuilder 等で実装しましょう。
メモリ効率もそのほうが有効です。

Stringのインスタンスは不変ですし、 
✕「引数に当てた変数の値を変更する」
◯「引数の変数の値を変更する」なので「引数に代入したもとの変数」は変わりません。

投稿2020/07/18 14:36

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

ベストアンサー

methodメソッドは以下のようなことをやっているという解釈であってますか。

はい、そのとおりです。


JavaのStringイミュータブルです。つまり、一度作られたインスタンスの中身を変える方法は存在しません

投稿2020/07/18 14:29

maisumakun

総合スコア145123

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

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

kobe2018

2020/07/18 14:34

ありがとうございます。 ちなみにもしお時間があったら・・・ String s1 = "a"; String s2 = new String(s1); とした場合、s1とs2は同値ではないと思います。 s2に代入されたのはs1の参照先(ヒープ上のアドレス)ではなく、s1の参照先の文字情報(この場合は"a")であってますか。
maisumakun

2020/07/18 14:36

s2に代入されたものは、s1とは別なStringのインスタンスです。
kobe2018

2020/07/18 14:38

そこがいまいちしっくりきてないです。 s1に格納されているのは参照先情報です。 それをs2に代入しているので最初は同値かと思いました。
maisumakun

2020/07/18 14:40

> それをs2に代入しているので していません。newで新たなStringを作って、それを代入しています(もっとも、イミュータブルである以上、実用的には別インスタンスを作る必要性はほぼゼロです)。
kobe2018

2020/07/18 14:42

すみません。 それ、とは"a"のことであってますか。参照先ではなく。
maisumakun

2020/07/18 14:44

> それ、とは"a"のことであってますか。 この表現自体が不適切です。同じ"a"という内容を持ったインスタンスは、複数存在しえます。
maisumakun

2020/07/18 14:45

「新たに作った、aを内容とする文字列のインスタンス」をs2に代入しています。
kobe2018

2020/07/18 14:46

そうですね。すみません。 s1の参照先に格納されている"a"に訂正します。
kobe2018

2020/07/18 14:46

ありがとうございます。
maisumakun

2020/07/18 14:47

> s1の参照先に格納されている"a"に訂正します。 違います。s1のインスタンスと同じ内容で、新たに作ったインスタンスです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問