Является ли Integer неизменным

Я знаю, что это, наверное, очень глупо, но многие места утверждают, что класс Integer в Java неизменен, но следующий код:

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

Выполняется без каких-либо проблем с получением (ожидаемого) результата 6. Таким образом, значение a изменилось. Разве это не означает, что Integer изменен? Вторичный вопрос и небольшой оффтоп: "Неизменяемым классам не нужны конструкторы копирования". Кто-нибудь должен объяснить, почему?

Ответ 1

Неизменность не означает, что a никогда не может равняться другому значению. Например, String тоже неизменен, но я все еще могу сделать это:

String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"

str не был изменен, скорее str теперь является полностью новым экземпляром объекта, как и ваш Integer. Таким образом, значение a не изменилось, но оно было заменено совершенно новым объектом, то есть new Integer(6).

Ответ 2

a является ссылкой на некоторое целое число (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.

Ответ 3

Вы можете определить, что объект изменился с помощью System.identityHashCode() (лучший способ - использовать plain ==, однако его не так очевидно, что ссылка вместо значения изменилась)

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

Вы можете видеть, что базовый "id" объекта a ссылается на него.

Ответ 4

К начальному вопросу, заданному,

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

Целое значение неизменено, поэтому произошедшее выше означает, что "a" изменилось на новую ссылку значения 6. Начальное значение 3 остается без ссылки в памяти (оно не было изменено), поэтому оно может быть сбор мусора.

Если это произойдет со строкой, она будет храниться в пуле (в пространстве PermGen) на более длительный период, чем целые, поскольку он ожидает наличия ссылок.

Ответ 5

Да Целое число является неизменным.

A является ссылкой, которая указывает на объект. Когда вы запускаете + = 3, это переназначает A для ссылки на новый объект Integer с другим значением.

Вы никогда не изменяли исходный объект, скорее, вы указали ссылку на другой объект.

Читайте о разнице между объектами и ссылками здесь.

Ответ 6

Неизменяемость не означает, что вы не можете изменить значение переменной. Это просто означает, что любое новое присваивание создает новый объект (присваивает ему новое местоположение памяти), а затем присваивается ему значение.

Чтобы понять это для себя, выполните назначение Integer в цикле (с объявлением целого за пределами цикла) и посмотрите на живые объекты в памяти.

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

Ответ 7

"Неизменяемым классам не нужны конструкторы копирования". Кто-нибудь должен объяснить, почему?

Причина в том, что редко требуется копировать (или даже любую точку копирования) экземпляр неизменяемого класса. Копия объекта должна быть "той же", что и "оригинал", и если это то же самое, ее не нужно создавать.

Есть некоторые основные предположения:

  • Предполагается, что ваше приложение не помещает никакого смысла в идентификатор объекта экземпляров класса.

  • Предполагается, что класс перегружен equals и hashCode, так что копия экземпляра будет "такой же, как" оригинал... согласно этим методам.

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

Ответ 8

Вот как я понимаю неизменный

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. Ваш пример - это просто новое задание.

Ответ 9

Я могу пояснить, что 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 100 вместо ожидаемого результата (в случае, если оба sb и я являются изменяемыми объектами) Привет Там 1000

Это показывает, что объект, созданный я в main, не изменяется, тогда как sb изменен.

Итак, StringBuilder продемонстрировал изменчивое поведение, но не Integer.

Итак, 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;
    }


}

Ответ 10

public static void main(String[] args) {
    // TODO Auto-generated method stub

    String s1="Hi";
    String s2=s1;

    s1="Bye";

    System.out.println(s2); //Hi  (if String was mutable output would be: Bye)
    System.out.println(s1); //Bye

    Integer i=1000;
    Integer i2=i;

    i=5000;

    System.out.println(i2); // 1000
    System.out.println(i); // 5000

    int j=1000;
    int j2=j;

    j=5000;

    System.out.println(j2); // 1000
    System.out.println(j); //  5000


    char c='a';
    char b=c;

    c='d';

    System.out.println(c); // d
    System.out.println(b); // a
}

Выход:

Привет до свидания 1000 5000 1000 5000 d а

Итак, char является изменяемым, String Integer и int неизменяемы.