Подтвердить что ты не робот

Являются ли примитивы Java неизменяемыми?

Если метод имеет локальную переменную i:

int i = 10;

а затем присвойте новое значение:

i = 11;

Будет ли это выделение новой ячейки памяти? Или просто замените исходное значение?

Означает ли это, что примитивы неизменяемы?

4b9b3361

Ответ 1

Будет ли это выделение новой ячейки памяти? Или просто замените исходное значение?

Java на самом деле не гарантирует, что переменные будут соответствовать ячейкам памяти; например, ваш метод может быть оптимизирован таким образом, что i хранится в регистре — или даже не может быть вообще сохранен, если компилятор может видеть, что вы никогда не используете его значение, или если он может отслеживать код и использовать соответствующие значения напрямую.

Но отложив это., если взять абстракцию здесь, чтобы локальная переменная обозначала ячейку памяти в стеке вызовов, тогда i = 11 будет просто изменять значение в этой ячейке памяти. Нет необходимости использовать новую ячейку памяти, потому что переменная i была единственной ссылкой на старое местоположение.

Означает ли это, что примитивы неизменяемы?

Да и нет: да, примитивы неизменяемы, но нет, это не из-за вышеперечисленного.

Когда мы говорим, что что-то изменено, мы имеем в виду, что он может быть мутирован: изменен, все еще имея ту же идентичность. Например, когда вы вырастите свои волосы, вы сами мутируете: вы все еще находитесь, но один из ваших атрибутов отличается.

В случае примитивов все их атрибуты полностью определяются их идентичностью; 1 всегда означает 1, независимо от того, что и 1 + 1 всегда 2. Вы не можете изменить это.

Если заданная переменная int имеет значение 1, вы можете изменить ее, чтобы вместо нее было значение 2, но это общее изменение личности: оно больше не имеет того же значения, которое было ранее. Это как изменение 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" как для ссылки на переменную (содержащую ссылку), так и на объект, на который он ссылается ( когда это относится к одному). Такая слабость прекрасна, если вы помните различие, когда это имеет значение.

Ответ 2

Immutable означает, что каждый раз, когда значение и объект изменилось, для него создается ссылка на стек. Вы не можете говорить о неизменности в случае примитивных типов, только классы Wrapper являются неизменными. Java использует copy_by_value не по ссылке.

Не имеет значения, передаете ли вы примитивные или ссылочные переменные, вы всегда передавая копию бит в переменную. Итак, для примитивной переменной вы передавая копию битов, представляющих значение, и если вы передаете ссылочную переменную объекта, вы передаете копию бит, представляющих ссылку на объект.

Например, если вы передаете переменную int со значением 3, вы передаете копию битов, представляющих 3.

Как только объявлен примитив, its primitive type can never change, хотя его значение может измениться.

Ответ 3

Это не полный ответ, но это способ доказать неизменность значений примитивного типа.

Если примитивные значения (литералы) изменяемы, тогда следующий код будет работать нормально:

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, уже сохранены в памяти. Когда вы устанавливаете переменную, равную одной из них: она изменяет значение в слоте памяти, где i.

Вы можете увидеть это здесь через байт-код для следующего кода:

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

Bytecode:

// 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, вы просто изменяете, какое значение хранится в этом слоте. Значения сами по себе не меняются, их расположение.

Ответ 4

Да, они неизменны. Они полностью неизменяемы.

Там хорошее объяснение похоронили в здесь. Это для Go, но это то же самое в Java. Или любой другой язык в семье C.