Вопрос:

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

java primitive

19845 просмотра

5 ответа

373 Репутация автора

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

int i = 10;

а затем я назначаю новое значение:

i = 11;

Будет ли это выделить новую область памяти? Или просто заменить первоначальное значение?

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

Автор: fYre Источник Размещён: 03.08.2013 08:38

Ответы (5)


7 плюса

237 Репутация автора

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

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

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

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

Автор: Java Panter Размещён: 03.08.2013 08:54

0 плюса

11293 Репутация автора

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

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

Автор: nes1983 Размещён: 03.08.2013 09:07

61 плюса

135974 Репутация автора

Решение

Будет ли это выделить новую область памяти? Или просто заменить первоначальное значение?

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» как для ссылки на переменную (которая содержит ссылку), так и на объект, на который она ссылается (когда он ссылается на единицу). Такая раскованность хороша, если вы помните различие, когда оно имеет значение.

Автор: ruakh Размещён: 03.08.2013 09:35

1 плюс

0 Репутация автора

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

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

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

Автор: user1181445 Размещён: 04.08.2013 01:32

0 плюса

339 Репутация автора

Примитивные литералы и finalпримитивные переменные неизменны. Не finalпримитивные переменные изменчивы.

Идентификацией любой примитивной переменной является имя этой переменной, и очевидно, что такая идентичность неизменна.

Автор: Rostislav Krasny Размещён: 09.09.2018 09:00
Вопросы из категории :
32x32