web-dev-qa-db-ja.com

整数不変

私はこれがおそらく非常に愚かであることを知っていますが、多くの場所がJavaのIntegerクラスは不変ですが、次のコードを主張しています:

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

(予期される)結果6を与える問題なく実行します。したがって、aの値は事実上変更されました。それは整数が可変であることを意味しませんか?二次的な質問と少しオフトピック:「不変クラスはコピーコンストラクタを必要としません」。誰が理由を説明したいですか?

91
K.Steff

不変とは、aが別の値と決して等しくなることができないという意味ではありません。たとえば、Stringも不変ですが、私はまだこれを行うことができます:

_String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"
_

そこで何が起こったのでしょうか? Stringは不変なので、明らかにstrは変更されませんでした。しかし、今ではそれは何か違うものに等しい。これは、strがそうであるように、Integerが完全に新しくインスタンス化されたオブジェクトであるためです。したがって、aの値は変化しませんでしたが、完全に新しいオブジェクト、つまりnew Integer(6)に置き換えられました。

88
Travis Webb

aは、いくつかのInteger(3)への「参照」であり、短縮形a+=bは実際にこれを行うことを意味します。

a = new Integer(3 + 3)

いいえ、整数は可変ではありませんが、それらを指す変数は*です。

*不変の変数を持つことは可能です。これらはキーワードfinalで示されます。これは、参照が変更されないことを意味します。

final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.
48
Mark Elliot

System.identityHashCode()を使用してオブジェクトが変更されたことを確認できます(より良い方法は、プレーン==ただし、値ではなく参照が変更されたことはそれほど明白ではありません)

Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));

プリント

before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda

aが参照するオブジェクトの基になる「id」が変更されていることがわかります。

17
Peter Lawrey

最初の質問に対して、

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

整数は不変であるため、上記で発生したことは、「a」が値6の新しい参照に変更されたことです。初期値3はメモリ内に参照なしで(変更されていないため)、ガベージコレクションできます。

これが文字列に発生した場合、参照があると予想される整数よりも長い期間プールに(PermGenスペースに)保持されます。

10
Harsha

はい整数は不変です。

Aは、オブジェクトを指す参照です。 + = 3を実行すると、Aを再割り当てして、異なる値を持つ新しいIntegerオブジェクトを参照します。

元のオブジェクトを変更したことはなく、参照を別のオブジェクトに向けました。

オブジェクトと参照の違いについて読む here

8
Andy

不変とは、変数の値を変更できないという意味ではありません。これは、新しい割り当てが新しいオブジェクトを作成し(新しいメモリ位置を割り当てる)、値が割り当てられることを意味します。

これを自分で理解するには、ループ内で整数の割り当てを実行し(ループ外で宣言された整数を使用)、メモリ内のライブオブジェクトを調べます。

不変オブジェクトにコピーコンストラクターが必要ない理由は、単純な常識です。割り当てごとに新しいオブジェクトが作成されるため、言語では技術的に既にコピーが作成されるため、別のコピーを作成する必要はありません。

3

「不変のクラスには、コピーコンストラクタは必要ありません」。誰が理由を説明したいですか?

その理由は、まれに不変クラスのインスタンスをコピーする必要がある(またはコピーするポイントさえ)ためです。オブジェクトのコピーはオリジナルと「同じ」である必要があり、同じ場合は作成する必要はありません。

ただし、いくつかの基本的な前提があります。

  • アプリケーションは、クラスのインスタンスのオブジェクトIDに意味を置かないと想定しています。

  • これらのメソッドによると、クラスのequalshashCodeがオーバーロードされているため、インスタンスのコピーは元の...と同じになります。

これらの仮定のいずれかまたは両方couldはfalseであり、コピーコンストラクターの追加が必要になる場合があります。

2
Stephen C

これは私が不変を理解する方法です

int a=3;    
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8

Intが変化する場合、「a」は8を出力しますが、不変であるために出力されません。そのため、3です。この例は、新しい割り当てです。

1
ndheti

Integer(およびFloat、Shortなどの信条)が単純なサンプルコードによって不変であることを明確にできます。

サンプルコード

public class Test{
    public static void main(String... args){
        Integer i = 100;
        StringBuilder sb = new StringBuilder("Hi");
        Test c = new Test();
        c.doInteger(i);
        c.doStringBuilder(sb);
        System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
    }

    private void doInteger(Integer i){
        i=1000;
    }

    private void doStringBuilder(StringBuilder sb){
        sb.append(" there");
    }

}

実際の結果

結果は彼に届くHi There 1予想される結果の代わりに(sbとiの両方が可変オブジェクトの場合)Hi There 10

これにより、mainでiによって作成されたオブジェクトは変更されず、sbが変更されます。

そのため、StringBuilderはIntegerではなく可変動作を示しました。

したがって、整数は不変です。 したがって証明済み

整数のみのない別のコード:

public class Test{
    public static void main(String... args){
        Integer i = 100;
        Test c = new Test();
        c.doInteger(i);
        System.out.println(i); //Expected result is 1000 in case Integer is mutable
    }

    private void doInteger(Integer i){
        i=1000;
    }


}
0
Ashutosh Nigam