Целочисленный неизменяемый - PullRequest
90 голосов
/ 06 апреля 2011

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

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

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

Ответы [ 10 ]

87 голосов
/ 06 апреля 2011

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

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

Так что там произошло?Поскольку String является неизменным, ясно, что str не изменился.Но теперь это что-то другое.Это потому, что str теперь является полностью новым экземпляром объекта, так же как и ваш Integer.Таким образом, значение a не изменилось, но было заменено совершенно новым объектом, то есть new Integer(6).

48 голосов
/ 06 апреля 2011

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.
17 голосов
/ 06 апреля 2011

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

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, изменился.

10 голосов
/ 09 сентября 2012

К первому заданному вопросу,

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

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

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

8 голосов
/ 06 апреля 2011

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

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

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

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

3 голосов
/ 06 апреля 2011

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

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

2 голосов
/ 06 апреля 2011

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

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

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

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

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

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

1 голос
/ 14 октября 2016

Вот так я понимаю неизменность

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

0 голосов
/ 09 октября 2017
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 неизменяемыми.

0 голосов
/ 04 апреля 2016

Я могу пояснить, что 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");
    }

}

Фактический результат

Результат приходит к нему Привет, Там 100 вместо ожидаемого результата (в случае обоихsb и i являются изменяемыми объектами) Привет, там 1000

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

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

Так что целое число является неизменным. Следовательно доказано

Другой код без единственного целого числа:

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;
    }


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...