Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Integer и int


Автор: Temdegon 19.3.2011, 19:16
Наткнулся на статью на Хабре
http://habrahabr.ru/blogs/java/104231/
про различия Integer и int , и про autoboxing.
В целом различия понятны, но я над ними никогда особо не задумывасля.
Некоторые моменты показались мне не очевидными, по этому решил поделиться этим линком с вами.

Автор: Pawl 19.3.2011, 20:26
Спасибо, статья интересная.

Автор: _Y_ 23.3.2011, 12:23
Цитата

Integer a1 = 50;
Integer a2 = 50;
.............
System.out.println(a1==a2);
Результатом выполнения будет:
true
.....
Здесь фактически вызывается статичный метод java.lang.Integer.valueOf(int), который, как вы можете увидеть в исходниках, кэширует значения от -128 до 127 

Интересно. Я этого не знал. Может кто-нибудь подскажет зачем это, собственно, нужно?

Автор: jk1 23.3.2011, 13:08
Цитата

Может кто-нибудь подскажет зачем это, собственно, нужно?


Собственно это реализация пула объектов в пределах диапазона byte. Удобно сравнивать указатели без вызова equals() и некоторая экономия памяти достигается за счет отсутствия дубликатов объектов. Этот механизм в некотором роде аналогичен интернированию строк.

Автор: _Y_ 23.3.2011, 15:16
Цитата(jk1 @ 23.3.2011,  13:08)
это реализация пула объектов в пределах диапазона byte. Удобно сравнивать указатели без вызова equals() и некоторая экономия памяти достигается за счет отсутствия дубликатов объектов.

Честно говоря, понятнее не стало.

Понятно, что -128 - 127 это byte, но разное поведение обьектов одного класса в зависимости от присвоенного значения.... Вах-вах какая красивая язык - и так испортить!

И, кстати, equals как раз сравнивает значения (ИМХО). А вот как в этом случае (-128 до 127) сравнить сами указатели?

Автор: jk1 23.3.2011, 15:21
Цитата

Понятно, что -128 - 127 это byte, но разное поведение обьектов одного класса в зависимости от присвоенного значения


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

Цитата

И, кстати, equals как раз сравнивает значения (ИМХО).


Вы меня не так поняли, перефразирую: "Нет необходимости вызывать equals для определения очевидного отношения равенства, можно выполнить сравнение указателей оператором ==. Из-за пулинга сравнение указателей равнозначно вызову equals(). Очевидно сравнение указателей происходит быстрее."

Автор: _Y_ 23.3.2011, 23:32
jk1, понятно. Спасибо.

Но вообще опасное это дело. Теперь ночами буду просыпаться, видя в кошмарах как Integer объекту присваивается значение меньше 128 smile

Кстати, в той статье автор горовил об Integer вроде как "например". Как быть в этом случае с другими подобными классами?

Автор: Temdegon 24.3.2011, 04:15
Мне все-таки кажется, что пул сделали для экономии памяти, ну и возможно, экономии времени на создание экземпляров. А возможность сравнения через == для byte это сайдэффект такой оптимизации, как и со String. И нефиг об этом задумываться. Правило четкое - обьекты сравнивать через equals! В JavaDoc к Integer тоже не написано, что можно сравнивать через ==.
Цитата

Удобно сравнивать указатели без вызова equals() 

Честно говоря, слабо представляю себе пример кода, где можно использовать такую оптимизацию. С одной стороны, если у вас есть константа, со значением 100, то вроде как можно юзать ==. Но с другой стороны, константы для того и выносят, чтоб удобно было потом ее поменять в одном месте. Было 100, станет 1000, и лазить по коду и выяснять, как вы там ее сравнивали, никто не будет. Да и вообще, если вы так уверены, что ваша константа будет ВСЕГДА попадать в byte, то почему вы объявили ее как Integer, а не как Byte?

С equals vs == для двух враперов мне вроде все понятно. Я про unboxing задумался:
вот есть прекрасный метод:
Код

    public static final Integer MEGA_CONST = 1000;
    public void check(int toCheck) {
        if (MEGA_CONST == toCheck) {
            System.out.println(toCheck + " = " + MEGA_CONST);
        } else {
            System.out.println(toCheck + " != " + MEGA_CONST);
        }
    }

все работает как задумано, проблем я не вижу. Потом читанул я статью на хабре, ну и решил, что мне надо бы тут параметр метода на Integer поменять. Или кто-то в интерфейсе поменял, и срефакторил побыстрому - int, Integer - какая нафиг разница. А в результате epic fail...

Цитата

Кстати, в той статье автор горовил об Integer вроде как "например". Как быть в этом случае с другими подобными классами?

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

Автор: _Y_ 24.3.2011, 15:36
Temdegon, ты прав, конечно. Сравнивать значения обьектов через == странновато. 

Но == можно использовать для сравнения указателей: на тот же обьект показывает или на другой (пусть и идентичный первому по состоянию своих атрибутов). Впрочем, не могу вообразить, так сразу, подобную надобу в плане Integer.

Автор: Старовъръ 25.3.2011, 20:36
Цитата
Кстати, в той статье автор горовил об Integer вроде как "например". Как быть в этом случае с другими подобными классами?
При автобоксинге вызывается метод Integer.valueOf() - вот в таких методах и смотри про другие классы. Например, Boolean имеет два значения и ими можно пользоваться всегда не создавая новые объекты Boolean'a (доступны как константы Boolean.FALSE, Boolean.TRUE). Например: 
Код
Boolean a = new Boolean(true); //создастся новый объект
Boolean b = Boolean.TRUE;//переиспользуется константа

По этой же причине (вызова метода valueOf()) и будет выброшен NPE, если в коде будет:
Код

Integer a = null;
//...
int b = a;
Такие же нюансы можно обнаружить и работая с таким классом, как String, который так же имеет пул констант, однако в отличие от обычных оберток, любая константа (то есть любая строка описанная прямо в коде), будет помещена в пул строк (это называется интернирование, пошло слово от метода String#intern(), который любую строку может поместить в пул). Таким образом:
Код

String a = "a";
Strinп b = "a";
String c = new String("a");//создаются два объекта! Первый - это "a" (хотя на самом деле она просто возьмется из пула, т.к. такая константа уже была выше), а второй - new String();
a.equals(b) - true
a == b - true

a.equals(c) - true
a == c - false!

String copyOfC = c.intern();
a == copyOfC - true!

Кстати, если вернуться к кешу Integer'ов, то его можно конфигурировать (задавать верхнюю границу) с помощью флага -XX:AutoBoxCacheMax=6132 во время запуска приложения.

Цитата
Но == можно использовать для сравнения указателей
Он используется только для сравнивания указателей, если мы говорим про объекты, а не про примитивы.

Автор: _Y_ 26.3.2011, 12:17
Старовъръ, кошмар какой!

Ну что поделать - планида значит наша такая smile 
____________________________________________
Вообще же - хорошо что обратили на это внимание.

Автор: Старовъръ 26.3.2011, 23:20
Если интересно, http://www.javatalks.ru/sutra110519.php#110519, решил написать небольшую статейку по теме (там еще в конце есть ссылка на другую статью, обязательно прочтите!).

Автор: _Y_ 27.3.2011, 10:41
Старовъръ, интересно и полезно. Единственно, во второй статье большие блоки кода без комментариев - читать весьма напряжно.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)