web-dev-qa-db-ja.com

Javaプリミティブは不変ですか?

メソッドにローカル変数iがある場合:

int i = 10;

そして、新しい値を割り当てます:

i = 11;

これにより、新しいメモリロケーションが割り当てられますか?または、元の値を置き換えるだけですか?

これは、プリミティブが不変であることを意味しますか?

34
fYre

これにより、新しいメモリロケーションが割り当てられますか?または、元の値を置き換えるだけですか?

Javaは、変数がメモリ位置に対応することを実際に保証しません。たとえば、iがレジスタに格納されるようにメソッドが最適化される場合があります。コンパイラが値を実際に使用したことがないことがわかる場合、またはコードをトレースして、適切な値を直接使用できます。

しかし、それは別として。 。 。ここで抽象化して、ローカル変数が呼び出しスタックのメモリ位置を示すとすると、i = 11はそのメモリ位置の値を単に変更します。変数iのみが古い場所を参照しているため、新しいメモリの場所を使用する必要はありません。

これは、プリミティブが不変であることを意味しますか?

はい、いいえ:はい、プリミティブは不変ですが、いいえ、それは上記の理由ではありません。

何かが可変であると言うとき、それは変異することができることを意味します:同じアイデンティティを持ちながら変更されます。たとえば、髪の毛が大きくなると、自分自身を変化させます。あなたはまだあなたですが、属性の1つが異なります。

プリミティブの場合、すべての属性はそのアイデンティティによって完全に決定されます。 1は常に1を意味し、1 + 1は常に2です。それを変えることはできません。

与えられたint変数の値が1の場合、代わりに2の値を持つように変更できますが、それはIDの完全な変更であり、同じ値ではなくなります前に持っていた。それはmeを私ではなく他の誰かを指すように変更するようなものです。実際にはmeを変更するのではなく、meを変更するだけです。

もちろん、オブジェクトを使用すると、多くの場合、両方を実行できます。

StringBuilder sb = new StringBuilder("foo");
sb.append("bar"); // mutate the object identified by sb
sb = new StringBuilder(); // change sb to identify a different object
sb = null; // change sb not to identify any object at all

一般的には、これらは両方とも「sbを変更する」と記述されます。これは、人々が両方とも「sb」を使用して変数(参照を含む)およびobjectが参照する(1つを参照する場合)。この種のゆるみは、区別が重要なときに覚えている限りは問題ありません。

59
ruakh

Immutableは、andの値が変更されるたびに、新しい参照がスタック上に作成されることを意味します。プリミティブ型の場合の不変性について話すことはできません。ラッパークラスのみが不変です。 Javaは参照ではなくcopy_by_valueを使用します。

プリミティブ変数または参照変数を渡す場合、違いはありません。常に変数のビットのコピーを渡します。したがって、プリミティブ変数の場合は、値を表すビットのコピーを渡します。オブジェクト参照変数を渡す場合は、オブジェクトへの参照を表すビットのコピーを渡します。

たとえば、値が3のint変数を渡すと、3を表すビットのコピーが渡されます。

プリミティブが宣言されると、its primitive type can never changeの値は変更できますが。

7
Java Panter

これは完全な答えではありませんが、プリミティブ型の値の不変性を証明する方法です。

プリミティブ値(リテラル)が可変の場合、次のコードは正常に機能します。

int i = 10; // assigned i the literal value of 10
5 = i; // reassign the value of 5 to equal 10
System.out.println(5); // prints 10

もちろん、これは真実ではありません。

5、10、11などの整数値は既にメモリに保存されています。それらの1つに等しい変数を設定すると、iが存在するメモリスロットの値が変更されます。

これは、次のコードのバイトコードで確認できます。

public void test(){
    int i = 10;
    i = 11;
    i = 10;
}

バイトコード:

// access flags 0x1
public test()V
 L0
  LINENUMBER 26 L0
  BIPUSH 10 // retrieve literal value 10
  ISTORE 1  // store it in value at stack 1: i
 L1
  LINENUMBER 27 L1
  BIPUSH 11 // same, but for literal value 11
  ISTORE 1
 L2
  LINENUMBER 28 L2
  BIPUSH 10 // repeat of first set. Still references the same literal 10. 
  ISTORE 1 
 L3
  LINENUMBER 29 L3
  RETURN
 L4
  LOCALVARIABLE this LTest; L0 L4 0
  LOCALVARIABLE i I L1 L4 1
  MAXSTACK = 1
  MAXLOCALS = 2

バイトコードでわかるように(できれば)、リテラル値(例:10)を参照し、変数iのスロットに格納します。 iの値を変更すると、そのスロットに保存される値が変更されます。値自体は変わらず、その場所は変わりません。

1
user1181445

プリミティブリテラルとfinalプリミティブ変数は不変です。 finalプリミティブ変数は可変ではありません。

プリミティブ変数のアイデンティティはその変数の名前であり、そのようなアイデンティティが変更できないことは明らかです。

0

はい、それらは不変です。それらは完全に不変です。

here には素敵な説明が埋め込まれています。 Go向けですが、Javaでも同じです。または、Cファミリーの他の言語。

0
nes1983