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

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

ただいまの
回答率

90.48%

  • Java

    14154questions

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

StringBuilderとStringの違い

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 910

sobue

score 166

public class AssignmentOperator {

    public static void main (String[] args){

        StringBuilder sb1 = new StringBuilder("abc");
        StringBuilder sb2 = sb1;
        sb1.append("de");

        System.out.println("sb1 = " + sb1);
        System.out.println("sb2 = " + sb2);

        String str1 = "ABC";
        String str2 = str1;
        str1 = str1 + "DE";

        System.out.println("str1 = " + str1);
        System.out.println("str2 = " + str2);
    }
}


上記のコードで
結果
sb1 = abcde
sb2 = abcde
str1 = ABCDE
str2 = ABC
になるのですが、StringとStringBuilderの文字列の連結結果が違うのが
中の処理がどうなっているかがわかりません。
宜しくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+2

まず、javaの代入はint,double,char,booleanなどの基本データ型を除いてすべて「参照を代入」します。
これは、「内容そのもの」をコピーしているのではなく、「内容への行き先」をコピーするということです。
なので、

StringBuilder sb1 = new StringBuilder("abc");
StringBuilder sb2 = sb1;


この処理で変数sb2とsb1は、実は「実態は同じもの」を指しています。

new StringBuilder("abc");


した時に、StringBuilderオブジェクトの本体がメモリ上に配置され、sb1はその本体への「行き先」を持ちます。

sb2=sb1


では、sb2はsb1と同じ「行き先」を持つようになります。行き先は同じですが、本体は一つしかありません。
sb2→StringBuilderの本体←sb1
というイメージです。

sb1.append("de");


これは、「sb1が持っている行き先のStringBuilderオブジェクト本体に"de"という文字列を追加せよ」という命令です。
sb2も同じものを指していますから、
sb1 = abcde 
sb2 = abcde 
となります。

次にStringクラスですが、これも参照代入なので、

String str1 = "ABC";
String str2 = str1;


この時点でstr1とstr2は実態は同じものを見ています。
ここで、実はStringクラスは不変オブジェクトなので、オブジェクトの中身を変えることができません。
なので、

str1 + "DE";


これは、「str1の指す文字列に"DE"という文字列を追加した新しい本体を作る」ことを意味しています。

str1 = str1 + "DE";


という代入式では、「str1の指す文字列に"DE"という文字列を追加した新しい本体を作り、その行き先を変数str1に新しく代入する」という処理になります。

この時参照の行き先は
str2 → 最初に作った”ABC” の本体
str1 → 先ほど新しく作成された”ABCDE” の本体
となるので、

str1 = ABCDE 
str2 = ABC 
となります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/05 19:05

    回答ありがとうございます。

    キャンセル

+1

StringとStringBuilderの違いという話しではなさそうな…?

StringBuilder sb1 = new StringBuilder("abc");
StringBuilder sb2 = sb1; ← sb2 と sb1 は「同じデータを指している状態」です(実体が1つで共有してる状態)
sb1.append("de"); ← sb1 の中身が変わったので同じ場所を指している sb2 も同じ結果になります

String str1 = "ABC"; ← str1 は "ABC" を指している(*)
String str2 = str1; ← str2 と str1 は「同じデータを指している状態」でここまでは上と同じです
str1 = str1 + "DE"; ← str1 が指している場所は (*)の"ABC"ではなく "ABCDE" という新しい別の場所を指すようになった

例えば
String str3 = str1 + "DE";
としたら分かり易いでしょうか?
この場合 str1 が指す場所は変化していませんよね?
またstr1が指す先の中身が直接編集(加工)されている訳でもありませんよね?
つまり「str1 = 」とstr1を新しい値で初期化しているので(*)の時に行ったstr1とは別の場所を指すように変化しているという事です。

ざっくりまとめると
・前者のケースでは2つは同じ場所を参照していて参照先の中身を直接(appendで)加工している
・後者のケースでは2つは途中まで同じ場所を参照していたが"DE"を追加した結果を参照するようにstr1の参照先を変更した時点でstr1とstr2の参照先が別物になった
という違いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/05 19:09

    表題に関しては表現があまり上手ではないので少し違うことを書いているかもしれませんが的確に答えていただきありがとうございます。

    キャンセル

+1

StringBuilderは可変オブジェクトです。appendなどのメソッドはオブジェクトが持つ情報を書き換えます。
一方、Stringは不変オブジェクトです。+演算子で文字の付け足しをしたり、メソッドで部分文字列を生成したりなどするときは、新たなStringオブジェクトを生成します。

また先の回答者様の通り、Javaにおいてプリミティブ型(int,long,doubleなどの数値型,文字型char,論理型boolean)を除き、すべて参照型です。代入の操作は、そのオブジェクトが存在する場所を入れています。その変数が見ているオブジェクトと考えればいいでしょう。

上記例では、最初の代入の段階ではStringBuilderの場合もStringの場合も、2つの変数が同じオブジェクトを見ている状態です。
StringBuilderの場合、変数sb1が見ているオブジェクトに対して「"de"を追加する」という操作をしています。ところが、このオブジェクトはsb2も見ているので、どちらの変数から出力してみても同じ結果が出てきます。
一方、Stringの場合、

str1 + "DE"


これはstr1が見ているStringに"DE"を追加した新しいStringを生成することを意味しています。元の"ABC"というStringには変化はありません。
そしてこれをstr1に代入するということは、str1が見る先がこの新しいStringに変わるということです。str2が"ABC"を見ていることに変化はないので、str1が"ABCDE",str2が"ABC"という結果になったのです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/05 19:10

    可変オブジェクト・不変オブジェクトという分け方があるのですね。非常に勉強になります。回答ありがとうございます。

    キャンセル

checkベストアンサー

0

まず、new StringBuilder("abc");で、メモリのどっかにオブジェクトが割り当てられる。
それを、StringBuilder sb1 = とすることで、sb1にオブジェクトの居場所握らせることができる。
それで、次のStringBuilder sb2 = sb1;ってのは、sb2にsb1が握っている居場所を伝えている。
だから、sb1とsb2は、new StringBuilder("abc");の同じ居場所を握っていることになる。
なので、
        System.out.println("sb1 = " + sb1);
        System.out.println("sb2 = " + sb2); 
は同じ結果になる。

さて、次に String str1 = "ABC";も、同様に、メモリのどっかにオブジェクトが割り当てられて、
str1にオブジェクトの居場所を握らせて、
String str2 = str1;で、str2にstr1が握っている居場所を伝えているわけだけど、
次のstr1 = str1 + "DE";と言うのは、str1のオブジェクトと"DE"というオブジェクトを連結させた新しいオブジェクトをメモリに割り当てて、その居場所をstr1に伝えている。
つまりこの時点で、str1とstr2の指し示すオブジェクトは別物になっている。

だから
        System.out.println("str1 = " + str1);
        System.out.println("str2 = " + str2);
は違う結果となるわけです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/05 19:14

    回答ありがとうございます。皆様とても詳しくベストアンサーは決めづらいのですが、個人的には一番わかりやすく答えていただいたので、ベストアンサーとさせていただきます。

    キャンセル

0

皆様の素晴らしい回答の通りなので、私から一点だけ補足させていただきます。

str1 = str1 + "DE";


str1 = (new StringBuilder()).append(str1).append("DE").toString();


と解釈されます。※ 古いバージョンのJavaではStringBuilderの代わりにStringBufferが使われます。

他の皆様がおっしゃるとおり、str1 + "DE"では新しいStringが作成されます。どういう風に作成されるかというと、上のコードのようになっていると言うことです。Stringに対する+演算子はメソッドや関数ではありません(C++やRubyとは大きく異なる点です)。ましてや、intなどの数字型とも異なる処理をします。StringBuffer(昔のJava)やStringBuilder(最近のJava)等を使って、文字列(数字の場合は文字列にした後)を連結し、新しい文字列を作るという動作をします。なお、連続して書いている場合は、一つのStringBuffer(またはStringBuilder)を使ってなるべく効率よく作るようになっています。新しいStringを作成されるとは何なのか?という答えが、このStringに対する+演算子の仕様と言うことです。
参考: Java 8 Language Specification | 15.18.1. String Concatenation Operator +

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/05 19:11

    補足、ありがとうございます。参考を入れていただいていますが英語が読めません・・・。
    やはり読めるようにならないとこの先厳しいのでしょうか?

    キャンセル

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

  • ただいまの回答率 90.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    getMethod、invokeの第2引数について

    こんなクラスがあったとします。 class Test { private Double A; private Integer B; private

  • 解決済

    Javaで文字列内の()かっこ内文字列を削除する

    Java言語で文字列操作の処理について質問があります。 文字列内に()かっこが含まれている場合、()内の文字列を削除する処理ロジックを書きたいです。 ()が一つの場合は、下記の

  • 解決済

    マッチしたものを書き換える

    マッチしたところの文字を書き換えるためにreplaceやreplaceAllなどを使わずにfor文を使って書き換えたいです。 ですが、ネットのどこにも例文がなく、行き詰っています

  • 解決済

    toString()メソッドのうまい書き方がわかりません。

    簡単な単方向連結リストの実装をしてみたのですが、toStringメソッドがうまく書けないで、困っています。 どのように記述するのがベストだと思われますか? public c

  • 受付中

    java.sql.Dateに変換するには?

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); java.sql.Date sqlDate = sdf.pa

  • 解決済

    ダブルクオーテーションで囲まれた文字を取得する方法

    Javaで ダブルクオーテーション「"」で囲まれた文字列を取得したいのですが、 Webを調べてもよい方法がヒットしませでした。 何かよい方法を知っている方、教えてください

  • 受付中

    java 三角形を造る

    for文で繰り返しの処理で どうゆう条件にしたら、⬛を繰り返して、 ⬛ ⬛⬛ ⬛⬛⬛ ⬛⬛⬛⬛ ⬛⬛⬛⬛⬛ を出せるのでしょう(・・;) 初心者ですので初歩的なソースコード

  • 解決済

    配列の分割方法について

    問題点 以下のような配列 String str[]={"ABC","DEFG","HI","KLM"} というのがあったとして、これを new_str[]={"A","B",・・・

同じタグがついた質問を見る

  • Java

    14154questions

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