以下のコードがいまいち理解できません。
自分なりの解釈を書いてみたので合っているか教えてください。
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ページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
Javaは参照渡しではないため、新たなオブジェクトを仮引数に代入しても呼び出し元側の実引数は変更されません。Stringが不変とかそういうのは今回は全く関係無いです。
まず、Javaでは、Stringオブジェクトや文字列リテラルに対する+
演算子(String Concatenation Operator +と言われる)は結合された新たなStringを生成します。一般的なJDKの実装では、StringBuilder(昔はStringBuffer)を用いて文字列を結合し、最後にStringに変換するという処理を行っています。つまり、s + "def"
は新たな別のStringです。それを、仮引数s
に代入していることになりますが、これは呼び出し元の実引数s
とは別物です。method
メソッドにおいて、全てのs
をx
に変えても同じ動きをすることからもそれはわかるでしょう。たまたま名前が同じなだけなので、ここは混同しないでください。そして、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
総合スコア21739
0
s = s + "def";
上記操作を行いたい場合は StringBuilder 等で実装しましょう。
メモリ効率もそのほうが有効です。
Stringのインスタンスは不変ですし、
✕「引数に当てた変数の値を変更する」
◯「引数の変数の値を変更する」なので「引数に代入したもとの変数」は変わりません。
投稿2020/07/18 14:36
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
methodメソッドは以下のようなことをやっているという解釈であってますか。
はい、そのとおりです。
JavaのString
はイミュータブルです。つまり、一度作られたインスタンスの中身を変える方法は存在しません。
投稿2020/07/18 14:29
総合スコア146018
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/18 14:36
2020/07/18 14:38
2020/07/18 14:40
2020/07/18 14:42
2020/07/18 14:44
2020/07/18 14:45
2020/07/18 14:46
2020/07/18 14:46
2020/07/18 14:47
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。