Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

copyすること

たとえば、
Vector b = new Vector(); b.add("abc");
Vector a = b;

とすると、aという新しいオブジェクトを作ったことになりませんよね。aを帰ればbも変わってしまうからです。

では、このルールはJava apiにあるすべてのクラスに適用するのでしょうか。

String の場合、普通にreferするだけでclone copyができてしまいますよね。

22

回答

2541

閲覧

22件の回答

評価

0

Stringは不変オブジェクト(イミュータブル)なんだよ。

評価

0

>String の場合、普通にreferするだけでclone copyができてしまいますよね。
Stringの内部を変更する方法があれば、同様にaを変えればbも変わります。
Stringの内部を変更する方法がないので、場合によってはコピーされているように見えるだけです。

評価

0

>String の場合、普通にreferするだけでclone copyができてしまいますよね。

インスタンスの中身を変更しているのではなく、新しくインスタンスを生成しているのに1票。

評価

0

ありがとうございます。

では、このようなオブジェクトはStringしかないのですね?あとは全部ただのreferに過ぎないということですね?

評価

0

Integerとかもそう。いろいろある。

評価

0

参照と実体の区別を、きちんとできるようにならないと、本質的な解決にはならんだろうな。

評価

0

>不良生徒さん
今回の件は参照と実体の区別は関係ありませんよ。
それに、新しくインスタンスを生成も関係ないですよ。

評価

0

そなの?
実体と参照をごっちゃにしているようにしか見えないんだけど。
をを、おいらが何かと別の何かをごっちゃにしているだけか。

評価

0

>普通にreferするだけでclone copyができてしまいますよね。
copyなどできていませんよ。
ここは、基礎だからきちんと理解しておかないと。

評価

0

新しくインスタンスを生成は関係なくも無いか。
String str1 = "str";
String str2 = str1;
str2.substring(1); // これではstr2の中身は変わらない
str2 = str2.substring(1); /* こうすると新しい文字列オブジェクトが生成されて、str2はそれを保持するようになる。*/

つまり、Stringオブジェクト(や他の不変オブジェクト)は状態を変化させることが出来ないようにできている。
これによって、何も考えずにメソッドに渡したり、メソッドの戻り値として使用できる。

public class ClassA {
    private String str;
    public ClassA(String str) {
        this.str = str;
    }
    public String getStr() {
        return str;
    }
}

これが、不変オブジェクトだと

public class ClassB {
    private StringBuilder str;
    public ClassB(StringBuilder str) {
        this.str = str;
    }
    public StringBuilder getStr() {
        return str;
    }
}

public class Main {
    public static void main(String[] args) {
        StringBuilder buf = new StringBuilder("str");
        ClassB b = new ClassB(buf);
        
        buf.append("aaa");
        System.out.println(b.getStr());
        
        b.getStr().append("bbb");
        System.out.println(b.getStr());
    }
}

と、カオスなものが出来上がる。

評価

0

String a = b;

では、aとbの実体は同じだということを、理解していないようです。
これがJavaScriptの話なら、実体のコピーになりますが。

コピーしたいのなら

String a = new String(b);

です。

評価

0

1つ注意。配列はもちろん不変じゃないから、

public ClassC {
    private String[] strs = new String[10];
    public String[] getStrs() {
        return strs;
    }
}

なんてやると、

public class Main {
    public static void main(String[] args) {
        ClassC c = new ClassC();
        for (int i = 0; i < 10; i++)
            c.getStrs()[i] = "str" + i;
        for (String str : c.getStrs())
            System.out.println(str);
    }
}

なんてことができてしまう。
"aaa,bbb,ccc".split(",")[1]
と同じ感覚だな。

評価

0

>とすると、aという新しいオブジェクトを作ったことになりませんよね。aを変ればbも変わってしまうからです。
最初から間違ってる。

評価

0

mioさん、

言葉使いが間違っているかもしれませんが、事実上
String a =b;
String a = new String(b);
は同じことをやっているんじゃないですか。

評価

0

まったく違います。基本からやり直しましょう。というよりオブジェクトがメモリーのアドレスをさすビット列だという(つまりCのポインタ)ということを理解しましょう。

評価

0

コンセプトとしてまったく違うということですが、Stringに関しては、結果として同じことでしょう?ここの「結果」とは、
String a =b;
String a = new String(b);

から得られるaとbを使って何をやっても結果は同じということです。

そうではない、という人がいれば、何か例を示して下さい。

評価

0

System.out.println(a == b);

評価

0

public class StringTest {
    public static void main(String[] args) {
        String b = "a";
        String a = b;
        System.out.println(b.equals(a));
        System.out.println(b == a);
        a = new String(b);
        System.out.println(b.equals(a));
        System.out.println(b == a);
    }
}

ここまで書けば分かりますか?
中身に入っている文字列を使う分には、もちろん同じですよ。

評価

0

良くわかりました。

「中身に入っている文字列を使う分には、もちろん同じですよ。」でやっとほっとしました:)

評価

0

意味的には同じだけど、パフォーマンスに差が出る可能性もある。
できる限り、
String a = new String(b);
とは書かないほうがいい。

評価

0

String やラッパークラスなどは 意味的に等しいとき equals で true を返すように書かれています。

評価

0

なるほど、中身は等しいということですね。

ありがとうございます。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。