「不変」という概念について混乱しています。私たちの教授は毎日「int は不変だ! 文字列は不変だ」と言っていますが、それは正確にはどういう意味ですか?
より一般的な質問ですが、データ構造が不変かどうかはどうすればわかりますか?
ありがとう
ここでの他の回答のいくつかは、可変性/不変性と値/参照セマンティクスを混同しているため、注意してください...
簡単に言えば、作成後に変更できる場合、エンティティは変更可能です。つまり、その値は時間の経過とともに変化する可能性があります。
まずは反例。JavaString
オブジェクトは不変です。String
値を変更するオブジェクトで呼び出すことができるメソッドはありません。
String a = "foo";
a.concat("bar");
System.out.println(a); // foo
代わりにこれを行うことができます:
String a = "foo";
a = a.concat("bar");
System.out.println(a); // foobar
しかし、それは新しいconcat()
オブジェクトを作成しているため機能し、参照はそのオブジェクトに再ポイントされます。現在、2 つのオブジェクトがあります。オリジナルは変更されていません (永久に失われているだけです)。 変更可能ですが、基になるオブジェクトはそうではありません。 String
a
String
a
int
変数については; C または Java では、これを行うことができます。
int x = 3;
x = 4; // Mutates x
x++; // Mutates x
x
単に新しい整数の「オブジェクト」を作成してそれを「再ポイント」するのではなく、これらが実際に mutate であることをどのように知ることができx
ますか? (プリミティブ型がオブジェクト型とは異なることを言語が保証しているという事実以外では。) C では、ある程度それを証明できます。
int x = 3;
int *p = x; // Pointer to original entity
x = 4;
printf("%d\n", *p); // 4
私の知る限り、Javaには同等のアプローチはありません。したがって、整数型が Java で本当に変更可能かどうかという問題は無関係であると主張できます。
特定の型が不変であるかどうかを知る方法については、ほとんどの場合、わかりません。少なくとも、それを調べたり、言われた約束を信じたりせずにはいられません.
Java では、ユーザー定義型が不変であることを保証するには、いくつかの単純な規則に従う必要があります (ここで説明されています)。しかし、これは単なる約束です。言語はそれを強制しません。
(変数ではなく、オブジェクトまたは値の) 不変性は通常、値のインプレース変更を行う方法がないことを意味します。(それへの他の参照に伝播するもの。)これは、次のようなものがある場合を意味します。
String a = "foo";
a
その値を変更するために実行できる操作はありません。つまり、次の動作を引き起こす仮説的な方法を使用することはできません。append()
String a = "foo";
a.append("bar"); // a is not reassigned
System.out.println(a); // prints "foobar"
これをコレクションのような変更可能なオブジェクトと対比することができます:
int[] as = new String[] { "foo" };
as[0] = "bar"; // we're changing `as` in-place - not the Strings stored in it
System.out.println(as[0]); // prints "bar"
プリミティブ型は、Java の例として最適な選択ではありません。プリミティブ型を複数参照することはできず、ミューテーションと再割り当ての違いを示す方法がないからです。
不変オブジェクトは言語に大きく依存しますが、不変オブジェクトは作成後に変更できないオブジェクトです。
これは通常、次のことを意味します。
int x = 4;
x = 5;//not 'allowed'
これは、int などのプリミティブを不変にできる言語 (Scala などの関数型言語など) で見られます。
OOP のほとんどのオブジェクトは、実際にはメモリ内の場所へのポインターです。そのオブジェクトが不変の場合、メモリ内のその場所の内容を変更することはできません。String
Javaの の場合、次のようなことが起こっています。
String a = "Hello"; //points to some memory location, lets say '0x00001'
a = a + " World!"; //points to a new locations, lets say '0x00002'
System.out.println(a);//prints the contents of memory location '0x00002'
この場合、a
は実際には 2 行目以降のメモリ内のまったく別の場所を指しています。これが意味することは、渡された別のスコープを持つ別のスレッドa
は "Hello World!" を認識しないということです。代わりに「こんにちは」:
String a = "Hello";
startThread(a, " Hello!");//starts some thread and passes a to it
startThread(b, " World!");//starts another thread and passes a to it
...
public void methodInThread(String a, String b) {
a = a + b;
System.out.println(a);
}
これら 2 つのスレッドは、呼び出された順序に関係なく、次を出力します。
"Hello Hello!" //thread 1
"Hello World!" //thread 2
通常、これは、型 (int など) でメソッドを呼び出すことができないことを意味します。
値型を不変と呼ぶことがあります
//theres no way for this to be mutable but this is an example of a value type
int a = 5
int b = a;
b=9
a のようなクラス型とは異なり、変更されません
MyClass a = new MyClass
MyClass b = a
b.DoSomething()
//a is now changed
不変オブジェクトとは、インスタンス化されると変更できないものです。変更が必要な場合は、新しいオブジェクトが作成され、参照がポイントされます。
また、int は不変ではありません。
Javaには、文字列、すべてのラッパークラスなどの不変のクラスがいくつかあります。Integer、Float、Long など
例: 整数 i=5; i=10; i=15;
Integer i=5 の場合、ここで新しい Integer オブジェクトが作成され、2 番目に i=10 ではなく、この値 10 が以前に作成されたオブジェクトに割り当てられ、別の新しいオブジェクトが作成されて i に割り当てられ、3 番目の i=15 がここに割り当てられます。再び新しいオブジェクトが作成され、再び i に割り当てられます。
注: int と Integer を混同しないでください。int はプリミティブ型で、Integer はラッパー クラスです。すべてのプリミティブは可変です。
構築後に状態を変更できないオブジェクトは、不変と見なされます。
ソース: http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html
可変性と不変性の概念は、コードが参照を保持する可能性があるものにのみ関連します。何かへの参照を保持し、その状態の不変の側面が何らかの値 (または状態) を持つことが観察される場合、その参照が存在する限り、その状態のその側面は常に同じ値を持つことが観察される可能性があります。 (州)。
String
文字列への参照を持ち、その文字列に「Hello」という文字が含まれていることを確認するコードは、いつでもそれを調べることができ、それらの文字が含まれていることを常に確認するため、Javaの型は不変であると合理的に説明できます。対照的に、あるChar[]
瞬間に「Hello」という文字が含まれていることが観察されたが、しばらくすると「Jello」という文字が含まれていることが観察される場合があります。したがって、 aChar[]
は変更可能と見なされます。
Java ではへの直接参照を保持することはできないため、int
可変性と不変性の概念は実際にはその型には当てはまりません。ただし、関連する への参照を保持することはできInteger
ます。特定の値を持つことが観察されたそのような参照は、常に同じ値を持ちます。したがって、Integer
は不変です。可変性と不変性の概念は のような値型には実際には適用できませんがint
、不変型の有用な側面を共有していることに注意してください: プリミティブ型の格納場所 (変数、フィールド、または配列要素) によって表される状態または、不変型は、その場所を新しい値または別の不変オブジェクトへの参照で上書きしない限り、変更されないことが保証されています。